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

This commit is contained in:
Seth Alves 2018-01-17 08:08:13 -08:00
commit 1e847cf32e
16 changed files with 249 additions and 21 deletions

View file

@ -537,6 +537,7 @@ void MyAvatar::simulate(float deltaTime) {
// we've achived our final adjusted position and rotation for the avatar
// and all of its joints, now update our attachements.
Avatar::simulateAttachments(deltaTime);
relayJointDataToChildren();
if (!_skeletonModel->hasSkeleton()) {
// All the simulation that can be done has been done

View file

@ -32,6 +32,8 @@
#include <shared/Camera.h>
#include <SoftAttachmentModel.h>
#include <render/TransitionStage.h>
#include "ModelEntityItem.h"
#include "RenderableModelEntityItem.h"
#include "Logging.h"
@ -347,6 +349,65 @@ void Avatar::updateAvatarEntities() {
setAvatarEntityDataChanged(false);
}
void Avatar::relayJointDataToChildren() {
forEachChild([&](SpatiallyNestablePointer child) {
if (child->getNestableType() == NestableType::Entity) {
auto modelEntity = std::dynamic_pointer_cast<RenderableModelEntityItem>(child);
if (modelEntity) {
if (modelEntity->getRelayParentJoints()) {
if (!modelEntity->getJointMapCompleted() || _reconstructSoftEntitiesJointMap) {
QStringList modelJointNames = modelEntity->getJointNames();
int numJoints = modelJointNames.count();
std::vector<int> map;
map.reserve(numJoints);
for (int jointIndex = 0; jointIndex < numJoints; jointIndex++) {
QString jointName = modelJointNames.at(jointIndex);
int avatarJointIndex = getJointIndex(jointName);
glm::quat jointRotation;
glm::vec3 jointTranslation;
if (avatarJointIndex < 0) {
jointRotation = modelEntity->getAbsoluteJointRotationInObjectFrame(jointIndex);
jointTranslation = modelEntity->getAbsoluteJointTranslationInObjectFrame(jointIndex);
map.push_back(-1);
} else {
int jointIndex = getJointIndex(jointName);
jointRotation = getJointRotation(jointIndex);
jointTranslation = getJointTranslation(jointIndex);
map.push_back(avatarJointIndex);
}
modelEntity->setLocalJointRotation(jointIndex, jointRotation);
modelEntity->setLocalJointTranslation(jointIndex, jointTranslation);
}
modelEntity->setJointMap(map);
} else {
QStringList modelJointNames = modelEntity->getJointNames();
int numJoints = modelJointNames.count();
for (int jointIndex = 0; jointIndex < numJoints; jointIndex++) {
int avatarJointIndex = modelEntity->avatarJointIndex(jointIndex);
glm::quat jointRotation;
glm::vec3 jointTranslation;
if (avatarJointIndex >=0) {
jointRotation = getJointRotation(avatarJointIndex);
jointTranslation = getJointTranslation(avatarJointIndex);
} else {
jointRotation = modelEntity->getAbsoluteJointRotationInObjectFrame(jointIndex);
jointTranslation = modelEntity->getAbsoluteJointTranslationInObjectFrame(jointIndex);
}
modelEntity->setLocalJointRotation(jointIndex, jointRotation);
modelEntity->setLocalJointTranslation(jointIndex, jointTranslation);
}
}
Transform avatarTransform = _skeletonModel->getTransform();
avatarTransform.setScale(_skeletonModel->getScale());
modelEntity->setOverrideTransform(avatarTransform, _skeletonModel->getOffset());
modelEntity->simulateRelayedJoints();
}
}
}
});
_reconstructSoftEntitiesJointMap = false;
}
void Avatar::simulate(float deltaTime, bool inView) {
PROFILE_RANGE(simulation, "simulate");
@ -379,6 +440,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
}
head->setScale(getModelScale());
head->simulate(deltaTime);
relayJointDataToChildren();
} else {
// a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated.
_skeletonModel->simulate(deltaTime, false);
@ -1197,6 +1259,7 @@ void Avatar::setModelURLFinished(bool success) {
invalidateJointIndicesCache();
_isAnimatingScale = true;
_reconstructSoftEntitiesJointMap = true;
if (!success && _skeletonModelURL != AvatarData::defaultFullAvatarModelUrl()) {
const int MAX_SKELETON_DOWNLOAD_ATTEMPTS = 4; // NOTE: we don't want to be as generous as ResourceCache is, we only want 4 attempts

View file

@ -330,6 +330,7 @@ protected:
// protected methods...
bool isLookingAtMe(AvatarSharedPointer avatar) const;
void relayJointDataToChildren();
void fade(render::Transaction& transaction, render::Transition::Type type);
@ -382,6 +383,7 @@ protected:
bool _isAnimatingScale { false };
bool _mustFadeIn { false };
bool _isFading { false };
bool _reconstructSoftEntitiesJointMap { false };
float _modelScale { 1.0f };
static int _jointConesID;

View file

@ -708,6 +708,26 @@ void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape)
}
}
void RenderableModelEntityItem::setJointMap(std::vector<int> jointMap) {
if (jointMap.size() > 0) {
_jointMap = jointMap;
_jointMapCompleted = true;
return;
}
_jointMapCompleted = false;
};
int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
int result = -1;
int mapSize = (int) _jointMap.size();
if (modelJointIndex >=0 && modelJointIndex < mapSize) {
result = _jointMap[modelJointIndex];
}
return result;
}
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
auto model = getModel();
if (EntityItem::contains(point) && model && _compoundShapeResource && _compoundShapeResource->isLoaded()) {
@ -813,6 +833,10 @@ bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int ind
return setLocalJointTranslation(index, jointRelativePose.trans());
}
bool RenderableModelEntityItem::getJointMapCompleted() {
return _jointMapCompleted;
}
glm::quat RenderableModelEntityItem::getLocalJointRotation(int index) const {
auto model = getModel();
if (model) {
@ -835,6 +859,13 @@ glm::vec3 RenderableModelEntityItem::getLocalJointTranslation(int index) const {
return glm::vec3();
}
void RenderableModelEntityItem::setOverrideTransform(const Transform& transform, const glm::vec3& offset) {
auto model = getModel();
if (model) {
model->overrideModelTransformAndOffset(transform, offset);
}
}
bool RenderableModelEntityItem::setLocalJointRotation(int index, const glm::quat& rotation) {
autoResizeJointArrays();
bool result = false;
@ -929,6 +960,26 @@ bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) {
return !result.isEmpty();
}
void RenderableModelEntityItem::simulateRelayedJoints() {
ModelPointer model = getModel();
if (model && model->isLoaded()) {
copyAnimationJointDataToModel();
model->simulate(0.0f);
model->updateRenderItems();
}
}
void RenderableModelEntityItem::stopModelOverrideIfNoParent() {
auto model = getModel();
if (model) {
bool overriding = model->isOverridingModelTransformAndOffset();
QUuid parentID = getParentID();
if (overriding && (!_relayParentJoints || parentID.isNull())) {
model->stopTransformAndOffsetOverride();
}
}
}
void RenderableModelEntityItem::copyAnimationJointDataToModel() {
auto model = getModel();
if (!model || !model->isLoaded()) {
@ -1280,6 +1331,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
}
entity->updateModelBounds();
entity->stopModelOverrideIfNoParent();
if (model->isVisible() != _visible) {
// FIXME: this seems like it could be optimized if we tracked our last known visible state in

View file

@ -81,8 +81,14 @@ public:
void setCollisionShape(const btCollisionShape* shape) override;
virtual bool contains(const glm::vec3& point) const override;
void stopModelOverrideIfNoParent();
virtual bool shouldBePhysical() const override;
void simulateRelayedJoints();
bool getJointMapCompleted();
void setJointMap(std::vector<int> jointMap);
int avatarJointIndex(int modelJointIndex);
void setOverrideTransform(const Transform& transform, const glm::vec3& offset);
// these are in the frame of this object (model space)
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
@ -90,7 +96,6 @@ public:
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override;
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override;
virtual glm::quat getLocalJointRotation(int index) const override;
virtual glm::vec3 getLocalJointTranslation(int index) const override;
virtual bool setLocalJointRotation(int index, const glm::quat& rotation) override;
@ -119,7 +124,9 @@ private:
void getCollisionGeometryResource();
GeometryResource::Pointer _compoundShapeResource;
bool _jointMapCompleted { false };
bool _originalTexturesRead { false };
std::vector<int> _jointMap;
QVariantMap _originalTextures;
bool _dimensionsInitialized { true };
bool _needsJointSimulation { false };

View file

@ -395,6 +395,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_SHAPE, shape);
CHECK_PROPERTY_CHANGE(PROP_DPI, dpi);
CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints);
changedProperties += _animation.getChangedProperties();
changedProperties += _keyLight.getChangedProperties();
@ -527,6 +528,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS, jointTranslations);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RELAY_PARENT_JOINTS, relayParentJoints);
}
if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) {
@ -755,6 +757,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread);
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints);
// Certifiable Properties
COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName);
@ -1163,6 +1166,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>);
ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector<bool>);
ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector<glm::vec3>);
ADD_PROPERTY_TO_MAP(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool);
ADD_PROPERTY_TO_MAP(PROP_SHAPE, Shape, shape, QString);
@ -1386,6 +1390,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, properties.getJointRotations());
APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, properties.getJointTranslationsSet());
APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, properties.getJointTranslations());
APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, properties.getRelayParentJoints());
}
if (properties.getType() == EntityTypes::Light) {
@ -1745,6 +1750,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS, QVector<glm::quat>, setJointRotations);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS_SET, QVector<bool>, setJointTranslationsSet);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS, QVector<glm::vec3>, setJointTranslations);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints);
}
if (properties.getType() == EntityTypes::Light) {
@ -2089,6 +2095,7 @@ void EntityItemProperties::markAllChanged() {
_owningAvatarIDChanged = true;
_dpiChanged = true;
_relayParentJointsChanged = true;
}
// The minimum bounding box for the entity.
@ -2455,6 +2462,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (jointTranslationsChanged()) {
out += "jointTranslations";
}
if (relayParentJointsChanged()) {
out += "relayParentJoints";
}
if (queryAACubeChanged()) {
out += "queryAACube";
}

View file

@ -255,6 +255,7 @@ public:
DEFINE_PROPERTY_REF(PROP_LAST_EDITED_BY, LastEditedBy, lastEditedBy, QUuid, ENTITY_ITEM_DEFAULT_LAST_EDITED_BY);
DEFINE_PROPERTY_REF(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString, ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS);
DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS);
static QString getComponentModeString(uint32_t mode);
static QString getComponentModeAsString(uint32_t mode);

View file

@ -92,4 +92,6 @@ const uint16_t ENTITY_ITEM_DEFAULT_DPI = 30;
const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid();
const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false;
#endif // hifi_EntityItemPropertiesDefaults_h

View file

@ -40,6 +40,7 @@ enum EntityPropertyList {
PROP_ANIMATION_FRAME_INDEX,
PROP_ANIMATION_PLAYING,
PROP_ANIMATION_ALLOW_TRANSLATION,
PROP_RELAY_PARENT_JOINTS,
// these properties are supported by the EntityItem base class
PROP_REGISTRATION_POINT,

View file

@ -62,7 +62,7 @@ EntityItemProperties ModelEntityItem::getProperties(EntityPropertyFlags desiredP
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotations, getJointRotations);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslationsSet, getJointTranslationsSet);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslations, getJointTranslations);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(relayParentJoints, getRelayParentJoints);
_animationProperties.getProperties(properties);
return properties;
}
@ -80,6 +80,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotations, setJointRotations);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslationsSet, setJointTranslationsSet);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslations, setJointTranslations);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(relayParentJoints, setRelayParentJoints);
bool somethingChangedInAnimations = _animationProperties.setProperties(properties);
@ -115,6 +116,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL);
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints);
int bytesFromAnimation;
withWriteLock([&] {
@ -155,6 +157,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
requestedProperties += PROP_JOINT_ROTATIONS;
requestedProperties += PROP_JOINT_TRANSLATIONS_SET;
requestedProperties += PROP_JOINT_TRANSLATIONS;
requestedProperties += PROP_RELAY_PARENT_JOINTS;
return requestedProperties;
}
@ -173,6 +176,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, getRelayParentJoints());
withReadLock([&] {
_animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties,
@ -586,6 +590,18 @@ QString ModelEntityItem::getModelURL() const {
});
}
void ModelEntityItem::setRelayParentJoints(bool relayJoints) {
withWriteLock([&] {
_relayParentJoints = relayJoints;
});
}
bool ModelEntityItem::getRelayParentJoints() const {
return resultWithReadLock<bool>([&] {
return _relayParentJoints;
});
}
QString ModelEntityItem::getCompoundShapeURL() const {
return _compoundShapeURL.get();
}

View file

@ -99,6 +99,9 @@ public:
void setAnimationHold(bool hold);
bool getAnimationHold() const;
void setRelayParentJoints(bool relayJoints);
bool getRelayParentJoints() const;
void setAnimationFirstFrame(float firstFrame);
float getAnimationFirstFrame() const;
@ -157,6 +160,7 @@ protected:
rgbColor _color;
QString _modelURL;
bool _relayParentJoints;
ThreadSafeValueCache<QString> _compoundShapeURL;

View file

@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::ZoneStageRemoved);
return static_cast<PacketVersion>(EntityVersion::SoftEntities);
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::RemovedJurisdictions);

View file

@ -205,7 +205,8 @@ enum class EntityVersion : PacketVersion {
StaticCertJsonVersionOne,
OwnershipChallengeFix,
ZoneLightInheritModes = 82,
ZoneStageRemoved
ZoneStageRemoved,
SoftEntities
};
enum class EntityScriptCallMethodVersion : PacketVersion {

View file

@ -145,7 +145,13 @@ void Model::setTransformNoUpdateRenderItems(const Transform& transform) {
}
Transform Model::getTransform() const {
if (_spatiallyNestableOverride) {
if (_overrideModelTransform) {
Transform transform;
transform.setTranslation(getOverrideTranslation());
transform.setRotation(getOverrideRotation());
transform.setScale(getScale());
return transform;
} else if (_spatiallyNestableOverride) {
bool success;
Transform transform = _spatiallyNestableOverride->getTransform(success);
if (success) {
@ -1381,6 +1387,14 @@ void Model::deleteGeometry() {
_collisionGeometry.reset();
}
void Model::overrideModelTransformAndOffset(const Transform& transform, const glm::vec3& offset) {
_overrideTranslation = transform.getTranslation();
_overrideRotation = transform.getRotation();
_overrideModelTransform = true;
setScale(transform.getScale());
setOffset(offset);
}
AABox Model::getRenderableMeshBound() const {
if (!isLoaded()) {
return AABox();

View file

@ -212,10 +212,15 @@ public:
void setTranslation(const glm::vec3& translation);
void setRotation(const glm::quat& rotation);
void overrideModelTransformAndOffset(const Transform& transform, const glm::vec3& offset);
bool isOverridingModelTransformAndOffset() { return _overrideModelTransform; };
void stopTransformAndOffsetOverride() { _overrideModelTransform = false; };
void setTransformNoUpdateRenderItems(const Transform& transform); // temporary HACK
const glm::vec3& getTranslation() const { return _translation; }
const glm::quat& getRotation() const { return _rotation; }
const glm::vec3& getOverrideTranslation() const { return _overrideTranslation; }
const glm::quat& getOverrideRotation() const { return _overrideRotation; }
glm::vec3 getNaturalDimensions() const;
@ -343,6 +348,9 @@ protected:
glm::quat _rotation;
glm::vec3 _scale;
glm::vec3 _overrideTranslation;
glm::quat _overrideRotation;
// For entity models this is the translation for the minimum extent of the model (in original mesh coordinate space)
// to the model's registration point. For avatar models this is the translation from the avatar's hips, as determined
// by the default pose, to the origin.
@ -403,6 +411,7 @@ protected:
QMutex _mutex;
bool _overrideModelTransform { false };
bool _triangleSetsValid { false };
void calculateTriangleSets();
QVector<TriangleSet> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes

View file

@ -57,7 +57,7 @@ ToggleButtonBuddy.prototype.addToggleHandler = function (callback) {
};
ToggleButtonBuddy.prototype.removeToggleHandler = function (callback) {
var index = this.callbacks.indexOf(callback);
if (index != -1) {
if (index !== -1) {
this.callbacks.splice(index, 1);
}
};
@ -86,13 +86,23 @@ var coatButton = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_
down: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-down.svg"
});
buttonPositionY += BUTTON_HEIGHT + BUTTON_PADDING;
var coatButton2 = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT, {
up: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-up.svg",
down: "https://s3.amazonaws.com/hifi-public/tony/icons/coat-down.svg"
});
var AVATAR_ATTACHMENT = 0;
var AVATAR_SOFT_ATTACHMENT = 1;
var ENTITY_ATTACHMENT = 2;
var HAT_ATTACHMENT = {
modelURL: "https://s3.amazonaws.com/hifi-public/tony/cowboy-hat.fbx",
jointName: "Head",
translation: {"x": 0, "y": 0.25, "z": 0.03},
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
scale: 0.052,
isSoft: false
type: AVATAR_ATTACHMENT
};
var COAT_ATTACHMENT = {
@ -101,7 +111,16 @@ var COAT_ATTACHMENT = {
translation: {"x": 0, "y": 0, "z": 0},
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
scale: 1,
isSoft: true
type: AVATAR_SOFT_ATTACHMENT
};
var COAT_ENTITY_ATTACHMENT = {
modelURL: "https://hifi-content.s3.amazonaws.com/ozan/dev/clothes/coat/coat_rig.fbx",
jointName: "Hips",
translation: {"x": 0, "y": 0, "z": 0},
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
scale: 1,
type: ENTITY_ATTACHMENT
};
hatButton.addToggleHandler(function (isDown) {
@ -120,28 +139,54 @@ coatButton.addToggleHandler(function (isDown) {
}
});
coatButton2.addToggleHandler(function (isDown) {
if (isDown) {
wearAttachment(COAT_ENTITY_ATTACHMENT);
} else {
removeAttachment(COAT_ENTITY_ATTACHMENT);
}
});
function wearAttachment(attachment) {
MyAvatar.attach(attachment.modelURL,
attachment.jointName,
attachment.translation,
attachment.rotation,
attachment.scale,
attachment.isSoft);
if (attachment.type === AVATAR_ATTACHMENT || attachment.type === AVATAR_SOFT_ATTACHMENT) {
MyAvatar.attach(attachment.modelURL,
attachment.jointName,
attachment.translation,
attachment.rotation,
attachment.scale,
(attachment.type === AVATAR_SOFT_ATTACHMENT));
} else {
attachment.entityID = Entities.addEntity({
name: "attachment",
type: "Model",
modelURL: attachment.modelURL,
parentID: MyAvatar.sessionUUID,
relayParentJoints: true,
position: attachment.position,
rotation: attachment.rotation,
parentJointIndex: -1
}, true);
}
}
function removeAttachment(attachment) {
var attachments = MyAvatar.attachmentData;
var i, l = attachments.length;
for (i = 0; i < l; i++) {
if (attachments[i].modelURL === attachment.modelURL) {
attachments.splice(i, 1);
MyAvatar.attachmentData = attachments;
break;
if (attachment.type === AVATAR_ATTACHMENT || attachment.type === AVATAR_SOFT_ATTACHMENT) {
var attachments = MyAvatar.attachmentData;
var i, l = attachments.length;
for (i = 0; i < l; i++) {
if (attachments[i].modelURL === attachment.modelURL) {
attachments.splice(i, 1);
MyAvatar.attachmentData = attachments;
break;
}
}
} else {
Entities.deleteEntity(attachment.entityID);
}
}
Script.scriptEnding.connect(function() {
hatButton.destroy();
coatButton.destroy();
coatButton2.destroy();
});