Turn attachments into avatar entities

This commit is contained in:
luiscuenca 2018-08-09 10:35:15 -07:00
parent 079b276c2b
commit 8c121a531d
3 changed files with 176 additions and 27 deletions

View file

@ -1688,16 +1688,6 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
markIdentityDataChanged();
}
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
Q_ARG(const QVector<AttachmentData>, attachmentData));
return;
}
Avatar::setAttachmentData(attachmentData);
emit attachmentsChanged();
}
glm::vec3 MyAvatar::getSkeletonPosition() const {
CameraMode mode = qApp->getCamera().getMode();
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) {
@ -1968,20 +1958,165 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
float scale, bool isSoft,
bool allowDuplicates, bool useSaved) {
if (QThread::currentThread() != thread()) {
Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved);
BLOCKING_INVOKE_METHOD(this, "attach",
Q_ARG(const QString&, modelURL),
Q_ARG(const QString&, jointName),
Q_ARG(const glm::vec3&, translation),
Q_ARG(const glm::quat&, rotation),
Q_ARG(float, scale),
Q_ARG(bool, isSoft),
Q_ARG(bool, allowDuplicates),
Q_ARG(bool, useSaved)
);
return;
}
if (useSaved) {
AttachmentData attachment = loadAttachmentData(modelURL, jointName);
if (attachment.isValid()) {
Avatar::attach(modelURL, attachment.jointName,
attachment.translation, attachment.rotation,
attachment.scale, attachment.isSoft,
allowDuplicates, useSaved);
return;
AttachmentData data;
data.modelURL = modelURL;
data.jointName = jointName;
data.translation = translation;
data.rotation = rotation;
data.scale = scale;
data.isSoft = isSoft;
EntityItemProperties properties;
attachmentDataToEntityProperties(data, properties);
DependencyManager::get<EntityScriptingInterface>()->addEntity(properties, true);
emit attachmentsChanged();
}
void MyAvatar::detachOne(const QString& modelURL, const QString& jointName) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "detachOne",
Q_ARG(const QString&, modelURL),
Q_ARG(const QString&, jointName)
);
return;
}
QUuid entityID;
if (findAvatarEntity(modelURL, jointName, entityID)) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(entityID);
}
emit attachmentsChanged();
}
void MyAvatar::detachAll(const QString& modelURL, const QString& jointName) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "detachAll",
Q_ARG(const QString&, modelURL),
Q_ARG(const QString&, jointName)
);
return;
}
QUuid entityID;
while (findAvatarEntity(modelURL, jointName, entityID)) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(entityID);
}
emit attachmentsChanged();
}
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
Q_ARG(const QVector<AttachmentData>&, attachmentData));
return;
}
std::vector<EntityItemProperties> newEntitiesProperties;
for (auto& data : attachmentData) {
QUuid entityID;
EntityItemProperties properties;
if (findAvatarEntity(data.modelURL.toString(), data.jointName, entityID)) {
properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
}
attachmentDataToEntityProperties(data, properties);
newEntitiesProperties.push_back(properties);
}
removeAvatarEntities();
for (auto& properties : newEntitiesProperties) {
DependencyManager::get<EntityScriptingInterface>()->addEntity(properties, true);
}
emit attachmentsChanged();
}
QVector<AttachmentData> MyAvatar::getAttachmentData() const {
QVector<AttachmentData> avatarData;
auto avatarEntities = getAvatarEntityData();
AvatarEntityMap::const_iterator dataItr = avatarEntities.begin();
while (dataItr != avatarEntities.end()) {
QUuid entityID = dataItr.key();
auto properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
AttachmentData data = entityPropertiesToAttachmentData(properties);
avatarData.append(data);
dataItr++;
}
return avatarData;
}
QVariantList MyAvatar::getAttachmentsVariant() const {
QVariantList result;
for (const auto& attachment : getAttachmentData()) {
result.append(attachment.toVariant());
}
return result;
}
void MyAvatar::setAttachmentsVariant(const QVariantList& variant) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "setAttachmentsVariant",
Q_ARG(const QVariantList&, variant));
return;
}
QVector<AttachmentData> newAttachments;
newAttachments.reserve(variant.size());
for (const auto& attachmentVar : variant) {
AttachmentData attachment;
if (attachment.fromVariant(attachmentVar)) {
newAttachments.append(attachment);
}
}
Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved);
setAttachmentData(newAttachments);
}
bool MyAvatar::findAvatarEntity(const QString& modelURL, const QString& jointName, QUuid& entityID) {
auto avatarEntities = getAvatarEntityData();
AvatarEntityMap::const_iterator dataItr = avatarEntities.begin();
while (dataItr != avatarEntities.end()) {
entityID = dataItr.key();
auto props = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
if (props.getModelURL() == modelURL &&
(jointName.isEmpty() || props.getParentJointIndex() == getJointIndex(jointName))) {
return true;
}
dataItr++;
}
return false;
}
AttachmentData MyAvatar::entityPropertiesToAttachmentData(const EntityItemProperties& properties) const {
AttachmentData data;
data.modelURL = properties.getModelURL();
data.translation = properties.getLocalPosition();
data.rotation = properties.getLocalRotation();
data.isSoft = properties.getRelayParentJoints();
quint16 jointIndex = properties.getParentJointIndex();
if (jointIndex > -1 && jointIndex < getJointNames().size()) {
data.jointName = getJointNames()[jointIndex];
}
return data;
}
void MyAvatar::attachmentDataToEntityProperties(const AttachmentData& data, EntityItemProperties& properties) {
QString url = data.modelURL.toString();
properties.setName(QFileInfo(url).baseName());
properties.setType(EntityTypes::Model);
properties.setParentID(getID());
properties.setOwningAvatarID(getID());
properties.setLocalPosition(data.translation);
properties.setLocalRotation(data.rotation);
if (!data.isSoft) {
properties.setParentJointIndex(getJointIndex(data.jointName));
} else {
properties.setRelayParentJoints(true);
}
properties.setModelURL(url);
}
void MyAvatar::initHeadBones() {

View file

@ -865,8 +865,6 @@ public:
void resetFullAvatarURL();
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
MyCharacterController* getCharacterController() { return &_characterController; }
const MyCharacterController* getCharacterController() const { return &_characterController; }
@ -1082,6 +1080,12 @@ public:
float computeStandingHeightMode(const controller::Pose& head);
glm::quat computeAverageHeadRotation(const controller::Pose& head);
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
virtual QVector<AttachmentData> getAttachmentData() const override;
virtual QVariantList getAttachmentsVariant() const override;
virtual void setAttachmentsVariant(const QVariantList& variant) override;
public slots:
/**jsdoc
@ -1506,11 +1510,21 @@ private:
void setScriptedMotorTimescale(float timescale);
void setScriptedMotorFrame(QString frame);
void setScriptedMotorMode(QString mode);
// Attachments
virtual void attach(const QString& modelURL, const QString& jointName = QString(),
const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(),
float scale = 1.0f, bool isSoft = false,
bool allowDuplicates = false, bool useSaved = true) override;
virtual void detachOne(const QString& modelURL, const QString& jointName = QString()) override;
virtual void detachAll(const QString& modelURL, const QString& jointName = QString()) override;
// Attachments/Avatar Entity
void attachmentDataToEntityProperties(const AttachmentData& data, EntityItemProperties& properties);
AttachmentData entityPropertiesToAttachmentData(const EntityItemProperties& properties) const;
bool findAvatarEntity(const QString& modelURL, const QString& jointName, QUuid& entityID);
bool cameraInsideHead(const glm::vec3& cameraPosition) const;
void updateEyeContactTarget(float deltaTime);

View file

@ -895,14 +895,14 @@ public:
* @returns {object}
*/
// FIXME: Can this name be improved? Can it be deprecated?
Q_INVOKABLE QVariantList getAttachmentsVariant() const;
Q_INVOKABLE virtual QVariantList getAttachmentsVariant() const;
/**jsdoc
* @function MyAvatar.setAttachmentsVariant
* @param {object} variant
*/
// FIXME: Can this name be improved? Can it be deprecated?
Q_INVOKABLE void setAttachmentsVariant(const QVariantList& variant);
Q_INVOKABLE virtual void setAttachmentsVariant(const QVariantList& variant);
/**jsdoc
@ -969,7 +969,7 @@ public:
* print (attachments[i].modelURL);
* }
*/
Q_INVOKABLE QVector<AttachmentData> getAttachmentData() const;
Q_INVOKABLE virtual QVector<AttachmentData> getAttachmentData() const;
/**jsdoc
* Set all models currently attached to your avatar. For example, if you retrieve attachment data using
@ -1040,7 +1040,7 @@ public:
* @param {string} [jointName=""] - The name of the joint to detach the model from. If <code>""</code>, then the most
* recently attached model is removed from which ever joint it was attached to.
*/
Q_INVOKABLE void detachOne(const QString& modelURL, const QString& jointName = QString());
Q_INVOKABLE virtual void detachOne(const QString& modelURL, const QString& jointName = QString());
/**jsdoc
* Detach all instances of a particular model from either a specific joint or all joints.
@ -1049,7 +1049,7 @@ public:
* @param {string} [jointName=""] - The name of the joint to detach the model from. If <code>""</code>, then the model is
* detached from all joints.
*/
Q_INVOKABLE void detachAll(const QString& modelURL, const QString& jointName = QString());
Q_INVOKABLE virtual void detachAll(const QString& modelURL, const QString& jointName = QString());
QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }