remove attachments

This commit is contained in:
HifiExperiments 2024-07-06 16:39:46 -07:00
parent 54d70a5679
commit 55907acd70
30 changed files with 19 additions and 1313 deletions

View file

@ -67,8 +67,6 @@
* @property {boolean} lookAtSnappingEnabled=true - <code>true</code> if the avatar's eyes snap to look at another avatar's
* eyes when the other avatar is in the line of sight and also has <code>lookAtSnappingEnabled == true</code>.
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @property {string[]} jointNames - The list of joints in the current avatar model. <em>Read-only.</em>
* @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. <em>Read-only.</em>
* @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the

View file

@ -316,7 +316,6 @@ static const QString JS_EXTENSION = ".js";
static const QString FST_EXTENSION = ".fst";
static const QString FBX_EXTENSION = ".fbx";
static const QString OBJ_EXTENSION = ".obj";
static const QString AVA_JSON_EXTENSION = ".ava.json";
static const QString WEB_VIEW_TAG = "noDownload=true";
static const QString ZIP_EXTENSION = ".zip";
static const QString CONTENT_ZIP_EXTENSION = ".content.zip";
@ -365,7 +364,6 @@ static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt";
const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions {
{ SVO_EXTENSION, &Application::importSVOFromURL },
{ SVO_JSON_EXTENSION, &Application::importSVOFromURL },
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl },
{ JSON_EXTENSION, &Application::importJSONFromURL },
{ JS_EXTENSION, &Application::askToLoadScript },
{ FST_EXTENSION, &Application::askToSetAvatarUrl },
@ -7838,74 +7836,6 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
return true;
}
bool Application::askToWearAvatarAttachmentUrl(const QString& url) {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QNetworkRequest networkRequest = QNetworkRequest(url);
networkRequest.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::OVERTE_USER_AGENT);
QNetworkReply* reply = networkAccessManager.get(networkRequest);
int requestNumber = ++_avatarAttachmentRequest;
connect(reply, &QNetworkReply::finished, [this, reply, url, requestNumber]() {
if (requestNumber != _avatarAttachmentRequest) {
// this request has been superseded by another more recent request
reply->deleteLater();
return;
}
QNetworkReply::NetworkError networkError = reply->error();
if (networkError == QNetworkReply::NoError) {
// download success
QByteArray contents = reply->readAll();
QJsonParseError jsonError;
auto doc = QJsonDocument::fromJson(contents, &jsonError);
if (jsonError.error == QJsonParseError::NoError) {
auto jsonObject = doc.object();
// retrieve optional name field from JSON
QString name = tr("Unnamed Attachment");
auto nameValue = jsonObject.value("name");
if (nameValue.isString()) {
name = nameValue.toString();
}
auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation");
auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?").arg(name);
ModalDialogListener* dlg = OffscreenUi::asyncQuestion(avatarAttachmentConfirmationTitle,
avatarAttachmentConfirmationMessage,
QMessageBox::Ok | QMessageBox::Cancel);
QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) {
QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr);
if (static_cast<QMessageBox::StandardButton>(answer.toInt()) == QMessageBox::Yes) {
// add attachment to avatar
auto myAvatar = getMyAvatar();
assert(myAvatar);
auto attachmentDataVec = myAvatar->getAttachmentData();
AttachmentData attachmentData;
attachmentData.fromJson(jsonObject);
attachmentDataVec.push_back(attachmentData);
myAvatar->setAttachmentData(attachmentDataVec);
} else {
qCDebug(interfaceapp) << "User declined to wear the avatar attachment";
}
});
} else {
// json parse error
auto avatarAttachmentParseErrorString = tr("Error parsing attachment JSON from url: \"%1\"");
displayAvatarAttachmentWarning(avatarAttachmentParseErrorString.arg(url));
}
} else {
// download failure
auto avatarAttachmentDownloadErrorString = tr("Error downloading attachment JSON from url: \"%1\"");
displayAvatarAttachmentWarning(avatarAttachmentDownloadErrorString.arg(url));
}
reply->deleteLater();
});
return true;
}
static const QString CONTENT_SET_NAME_QUERY_PARAM = "name";
void Application::replaceDomainContent(const QString& url, const QString& itemName) {
@ -7984,11 +7914,6 @@ bool Application::askToReplaceDomainContent(const QString& url) {
return true;
}
void Application::displayAvatarAttachmentWarning(const QString& message) const {
auto avatarAttachmentWarningTitle = tr("Avatar Attachment Failure");
OffscreenUi::asyncWarning(avatarAttachmentWarningTitle, message);
}
void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const {
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet(SYSTEM_TABLET);
auto hmd = DependencyManager::get<HMDScriptingInterface>();

View file

@ -546,9 +546,6 @@ private slots:
bool askToSetAvatarUrl(const QString& url);
bool askToLoadScript(const QString& scriptFilenameOrURL);
bool askToWearAvatarAttachmentUrl(const QString& url);
void displayAvatarAttachmentWarning(const QString& message) const;
bool askToReplaceDomainContent(const QString& url);
void setSessionUUID(const QUuid& sessionUUID) const;
@ -800,8 +797,6 @@ private:
bool _reticleClickPressed { false };
bool _keyboardFocusWaitingOnRenderable { false };
int _avatarAttachmentRequest = 0;
bool _settingsLoaded { false };
bool _captureMouse { false };

View file

@ -222,8 +222,6 @@ void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) {
* @property {number} avatarScale - The target scale of the avatar.
* @property {Array<Object<"properties",Entities.EntityProperties>>} [avatarEntites] - The avatar entities included with the
* bookmark.
* @property {AttachmentData[]} [attachments] - The attachments included with the bookmark.
* <p class="important">Deprecated: Use avatar entities instead.
*/
void AvatarBookmarks::loadBookmark(const QString& bookmarkName) {
@ -266,8 +264,6 @@ void AvatarBookmarks::loadBookmarkInternal(const QString& bookmarkName) {
myAvatar->clearWornAvatarEntities();
const float& qScale = bookmark.value(ENTRY_AVATAR_SCALE, 1.0f).toFloat();
myAvatar->setAvatarScale(qScale);
QList<QVariant> attachments = bookmark.value(ENTRY_AVATAR_ATTACHMENTS, QList<QVariant>()).toList();
myAvatar->setAttachmentsVariant(attachments);
QVariantList avatarEntities = bookmark.value(ENTRY_AVATAR_ENTITIES, QVariantList()).toList();
addAvatarEntities(avatarEntities);
emit bookmarkLoaded(bookmarkName);
@ -335,7 +331,6 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() {
const QString& avatarIcon = QString("");
const QVariant& avatarScale = myAvatar->getAvatarScale();
// If Avatar attachments ever change, this is where to update them, when saving remember to also append to AVATAR_BOOKMARK_VERSION
QVariantMap bookmark;
bookmark.insert(ENTRY_VERSION, AVATAR_BOOKMARK_VERSION);
bookmark.insert(ENTRY_AVATAR_URL, avatarUrl);

View file

@ -66,8 +66,7 @@ public slots:
void saveBookmark(const QString& bookmarkName);
/*@jsdoc
* Loads an avatar bookmark, setting your avatar model, scale, and avatar entities (or attachments if an old bookmark) to
* those in the bookmark.
* Loads an avatar bookmark, setting your avatar model, scale, and avatar entities to those in the bookmark.
* @function AvatarBookmarks.loadBookmark
* @param {string} bookmarkName - The name of the avatar bookmark to load (case sensitive).
*/
@ -104,8 +103,7 @@ public slots:
signals:
/*@jsdoc
* Triggered when an avatar bookmark is loaded, setting your avatar model, scale, and avatar entities (or attachments if an
* old bookmark) to those in the bookmark.
* Triggered when an avatar bookmark is loaded, setting your avatar model, scale, and avatar entities to those in the bookmark.
* @function AvatarBookmarks.bookmarkLoaded
* @param {string} bookmarkName - The name of the avatar bookmark loaded.
* @returns {Signal}
@ -155,7 +153,6 @@ private:
const QString AVATARBOOKMARKS_FILENAME = "avatarbookmarks.json";
const QString ENTRY_AVATAR_URL = "avatarUrl";
const QString ENTRY_AVATAR_ICON = "avatarIcon";
const QString ENTRY_AVATAR_ATTACHMENTS = "attachments";
const QString ENTRY_AVATAR_ENTITIES = "avatarEntites";
const QString ENTRY_AVATAR_SCALE = "avatarScale";
const QString ENTRY_VERSION = "version";

View file

@ -272,12 +272,6 @@ MyAvatar::MyAvatar(QThread* thread) :
auto hfmModel = getSkeletonModel()->getHFMModel();
qApp->loadAvatarScripts(hfmModel.scripts);
_shouldLoadScripts = false;
}
// Load and convert old attachments to avatar entities
if (_oldAttachmentData.size() > 0) {
setAttachmentData(_oldAttachmentData);
_oldAttachmentData.clear();
_attachmentData.clear();
}
});
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
@ -371,10 +365,6 @@ MyAvatar::MyAvatar(QThread* thread) :
setWorldPosition(dummyAvatar.getWorldPosition());
setWorldOrientation(dummyAvatar.getWorldOrientation());
if (!dummyAvatar.getAttachmentData().isEmpty()) {
setAttachmentData(dummyAvatar.getAttachmentData());
}
auto headData = dummyAvatar.getHeadData();
if (headData && _headData) {
// blendshapes
@ -501,11 +491,6 @@ glm::quat MyAvatar::getOrientationOutbound() const {
return (slerp(_smoothOrientationInitial, _smoothOrientationTarget, interp));
}
// virtual
void MyAvatar::simulateAttachments(float deltaTime) {
// don't update attachments here, do it in harvestResultsFromPhysicsSimulation()
}
QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) {
CameraMode mode = qApp->getCamera().getMode();
_globalPosition = getWorldPosition();
@ -982,8 +967,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
}
// we've achived our final adjusted position and rotation for the avatar
// and all of its joints, now update our attachements.
Avatar::simulateAttachments(deltaTime);
// and all of its joints, now update our children.
relayJointDataToChildren();
if (applyGrabChanges()) {
_cauterizationNeedsUpdate = true;
@ -2175,65 +2159,6 @@ void MyAvatar::loadAvatarEntityDataFromSettings() {
});
}
void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const {
Settings settings;
settings.beginGroup("savedAttachmentData");
settings.beginGroup(_skeletonModel->getURL().toString());
settings.beginGroup(attachment.modelURL.toString());
settings.setValue("jointName", attachment.jointName);
settings.beginGroup(attachment.jointName);
settings.setValue("translation_x", attachment.translation.x);
settings.setValue("translation_y", attachment.translation.y);
settings.setValue("translation_z", attachment.translation.z);
glm::vec3 eulers = safeEulerAngles(attachment.rotation);
settings.setValue("rotation_x", eulers.x);
settings.setValue("rotation_y", eulers.y);
settings.setValue("rotation_z", eulers.z);
settings.setValue("scale", attachment.scale);
settings.endGroup();
settings.endGroup();
settings.endGroup();
settings.endGroup();
}
AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& jointName) const {
Settings settings;
settings.beginGroup("savedAttachmentData");
settings.beginGroup(_skeletonModel->getURL().toString());
settings.beginGroup(modelURL.toString());
AttachmentData attachment;
attachment.modelURL = modelURL;
if (jointName.isEmpty()) {
attachment.jointName = settings.value("jointName").toString();
} else {
attachment.jointName = jointName;
}
settings.beginGroup(attachment.jointName);
if (settings.contains("translation_x")) {
attachment.translation.x = loadSetting(settings, "translation_x", 0.0f);
attachment.translation.y = loadSetting(settings, "translation_y", 0.0f);
attachment.translation.z = loadSetting(settings, "translation_z", 0.0f);
glm::vec3 eulers;
eulers.x = loadSetting(settings, "rotation_x", 0.0f);
eulers.y = loadSetting(settings, "rotation_y", 0.0f);
eulers.z = loadSetting(settings, "rotation_z", 0.0f);
attachment.rotation = glm::quat(eulers);
attachment.scale = loadSetting(settings, "scale", 1.0f);
} else {
attachment = AttachmentData();
}
settings.endGroup();
settings.endGroup();
settings.endGroup();
settings.endGroup();
return attachment;
}
bool MyAvatar::isMyAvatarURLProtected() const {
return !ScriptPermissions::isCurrentScriptAllowed(ScriptPermissions::Permission::SCRIPT_PERMISSION_GET_AVATAR_URL);
}
@ -2994,171 +2919,6 @@ SharedSoundPointer MyAvatar::getCollisionSound() {
return _collisionSound;
}
void MyAvatar::attach(const QString& modelURL, const QString& jointName,
const glm::vec3& translation, const glm::quat& rotation,
float scale, bool isSoft,
bool allowDuplicates, bool useSaved) {
if (QThread::currentThread() != thread()) {
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 (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring attach() because don't have canRezAvatarEntities permission on domain";
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;
}
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring detachOne() because don't have canRezAvatarEntities permission on domain";
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;
}
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring detachAll() because don't have canRezAvatarEntities permission on domain";
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;
}
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring setAttachmentData() because don't have canRezAvatarEntities permission on domain";
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);
}
// clear any existing wearables
clearWornAvatarEntities();
for (auto& properties : newEntitiesProperties) {
DependencyManager::get<EntityScriptingInterface>()->addEntity(properties, true);
}
emit attachmentsChanged();
}
QVector<AttachmentData> MyAvatar::getAttachmentData() const {
QVector<AttachmentData> attachmentData;
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring getAttachmentData() because don't have canRezAvatarEntities permission on domain";
return attachmentData;
}
QList<QUuid> avatarEntityIDs;
_avatarEntitiesLock.withReadLock([&] {
avatarEntityIDs = _packedAvatarEntityData.keys();
});
for (const auto& entityID : avatarEntityIDs) {
auto properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
AttachmentData data = entityPropertiesToAttachmentData(properties);
attachmentData.append(data);
}
return attachmentData;
}
QVariantList MyAvatar::getAttachmentsVariant() const {
QVariantList result;
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp)
<< "Ignoring getAttachmentsVariant() because don't have canRezAvatarEntities permission on domain";
return 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;
}
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp)
<< "Ignoring setAttachmentsVariant() because don't have canRezAvatarEntities permission on domain";
return;
}
QVector<AttachmentData> newAttachments;
newAttachments.reserve(variant.size());
for (const auto& attachmentVar : variant) {
AttachmentData attachment;
if (attachment.fromVariant(attachmentVar)) {
newAttachments.append(attachment);
}
}
setAttachmentData(newAttachments);
}
bool MyAvatar::findAvatarEntity(const QString& modelURL, const QString& jointName, QUuid& entityID) {
QList<QUuid> avatarEntityIDs;
_avatarEntitiesLock.withReadLock([&] {
@ -3174,34 +2934,6 @@ bool MyAvatar::findAvatarEntity(const QString& modelURL, const QString& jointNam
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();
int jointIndex = (int)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(AVATAR_SELF_ID);
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() {
int neckJointIndex = -1;
if (_skeletonModel->isLoaded()) {
@ -3444,22 +3176,6 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
if (shouldDrawHead != _prevShouldDrawHead) {
_cauterizationNeedsUpdate = true;
_skeletonModel->setEnableCauterization(!shouldDrawHead);
for (int i = 0; i < _attachmentData.size(); i++) {
if (_attachmentData[i].jointName.compare("Head", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Neck", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("LeftEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) {
uint8_t modelRenderTagBits = shouldDrawHead ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_SECONDARY_VIEW;
_attachmentModels[i]->setTagMask(modelRenderTagBits);
_attachmentModels[i]->setGroupCulled(false);
_attachmentModels[i]->setCanCastShadow(true);
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene());
}
}
}
_prevShouldDrawHead = shouldDrawHead;
}

View file

@ -141,8 +141,6 @@ class MyAvatar : public Avatar {
* @property {boolean} lookAtSnappingEnabled=true - <code>true</code> if the avatar's eyes snap to look at another avatar's
* eyes when the other avatar is in the line of sight and also has <code>lookAtSnappingEnabled == true</code>.
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @property {string[]} jointNames - The list of joints in the current avatar model. <em>Read-only.</em>
* @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. <em>Read-only.</em>
* @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the
@ -326,17 +324,10 @@ class MyAvatar : public Avatar {
* @borrows Avatar.getJointIndex as getJointIndex
* @borrows Avatar.getJointNames as getJointNames
* @borrows Avatar.setBlendshape as setBlendshape
* @borrows Avatar.getAttachmentsVariant as getAttachmentsVariant
* @borrows Avatar.setAttachmentsVariant as setAttachmentsVariant
* @borrows Avatar.updateAvatarEntity as updateAvatarEntity
* @borrows Avatar.clearAvatarEntity as clearAvatarEntity
* @borrows Avatar.setForceFaceTrackerConnected as setForceFaceTrackerConnected
* @borrows Avatar.setSkeletonModelURL as setSkeletonModelURL
* @borrows Avatar.getAttachmentData as getAttachmentData
* @borrows Avatar.setAttachmentData as setAttachmentData
* @borrows Avatar.attach as attach
* @borrows Avatar.detachOne as detachOne
* @borrows Avatar.detachAll as detachAll
* @comment Avatar.getAvatarEntityData as getAvatarEntityData - Don't borrow because implementation is different.
* @comment Avatar.setAvatarEntityData as setAvatarEntityData - Don't borrow because implementation is different.
* @borrows Avatar.getSensorToWorldMatrix as getSensorToWorldMatrix
@ -590,8 +581,6 @@ public:
static void registerMetaTypes(ScriptEnginePointer engine);
void registerProperties(ScriptEnginePointer engine);
virtual void simulateAttachments(float deltaTime) override;
AudioListenerMode getAudioListenerModeHead() const { return FROM_HEAD; }
AudioListenerMode getAudioListenerModeCamera() const { return FROM_CAMERA; }
AudioListenerMode getAudioListenerModeCustom() const { return CUSTOM; }
@ -1073,9 +1062,6 @@ public:
void loadData();
void loadAvatarEntityDataFromSettings();
void saveAttachmentData(const AttachmentData& attachment) const;
AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const;
// Set what driving keys are being pressed to control thrust levels
void clearDriveKeys();
void setDriveKey(DriveKeys key, float val);
@ -1822,12 +1808,6 @@ 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;
glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); }
void prepareAvatarEntityDataForReload();
@ -2610,16 +2590,6 @@ signals:
*/
void sensorToWorldScaleChanged(float sensorToWorldScale);
/*@jsdoc
* Triggered when the a model is attached to or detached from one of the avatar's joints using one of
* {@link MyAvatar.attach|attach}, {@link MyAvatar.detachOne|detachOne}, {@link MyAvatar.detachAll|detachAll}, or
* {@link MyAvatar.setAttachmentData|setAttachmentData}.
* @function MyAvatar.attachmentsChanged
* @returns {Signal}
* @deprecated This signal is deprecated and will be removed. Use avatar entities instead.
*/
void attachmentsChanged();
/*@jsdoc
* Triggered when the avatar's size changes. This can be due to the user changing the size of their avatar or the domain
* limiting the size of their avatar.
@ -2701,18 +2671,7 @@ private:
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;
// Avatar Entities
bool findAvatarEntity(const QString& modelURL, const QString& jointName, QUuid& entityID);
void addAvatarEntitiesToTree();

View file

@ -316,7 +316,6 @@ void OtherAvatar::simulate(float deltaTime, bool inView) {
{
PROFILE_RANGE(simulation, "misc");
measureMotionDerivatives(deltaTime);
simulateAttachments(deltaTime);
updatePalms();
}
{
@ -384,7 +383,7 @@ void OtherAvatar::debugJointData() const {
}
void OtherAvatar::handleChangedAvatarEntityData() {
PerformanceTimer perfTimer("attachments");
PerformanceTimer perfTimer("avatarEntities");
// AVATAR ENTITY UPDATE FLOW
// - if queueEditEntityMessage() sees "AvatarEntity" HostType it calls _myAvatar->storeAvatarEntityDataPayload()

View file

@ -20,14 +20,10 @@
#include "HMDToolsDialog.h"
#include "TestingDialog.h"
class AnimationsDialog;
class AttachmentsDialog;
class CachesSizeDialog;
class LodToolsDialog;
class OctreeStatsDialog;
class ScriptEditorWindow;
class TestingDialog;
class QMessageBox;
class DomainConnectionDialog;
class DialogsManager : public QObject, public Dependency {
@ -77,10 +73,6 @@ private:
template<typename T>
void maybeCreateDialog(QPointer<T>& member);
QPointer<AnimationsDialog> _animationsDialog;
QPointer<AttachmentsDialog> _attachmentsDialog;
QPointer<CachesSizeDialog> _cachesSizeDialog;
QPointer<QMessageBox> _ircInfoBox;
QPointer<HMDToolsDialog> _hmdToolsDialog;
QPointer<LodToolsDialog> _lodToolsDialog;
QPointer<OctreeStatsDialog> _octreeStatsDialog;

View file

@ -32,7 +32,7 @@
#include <NetworkingConstants.h>
#include <SharedUtil.h>
const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "skeletons", "attachments" };
const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "skeletons" };
static const QString S3_URL = NetworkingConstants::HF_PUBLIC_CDN_URL;
static const QString PUBLIC_URL = "http://public.overte.org"; // Changed to Overte but not entirely sure what to do with this yet.

View file

@ -30,7 +30,6 @@
#include <VariantMapToScriptValue.h>
#include <DebugDraw.h>
#include <shared/Camera.h>
#include <SoftAttachmentModel.h>
#include <render/TransitionStage.h>
#include <GLMHelpers.h>
#include "ModelEntityItem.h"
@ -52,7 +51,6 @@ const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
const float Avatar::MYAVATAR_LOADING_PRIORITY = (float)M_PI; // Entity priority is computed as atan2(maxDim, distance) which is <= PI / 2
const float Avatar::OTHERAVATAR_LOADING_PRIORITY = MYAVATAR_LOADING_PRIORITY - EPSILON;
const float Avatar::ATTACHMENT_LOADING_PRIORITY = OTHERAVATAR_LOADING_PRIORITY - EPSILON;
namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
@ -651,19 +649,6 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
processMaterials();
bool attachmentRenderingNeedsUpdate = false;
for (auto& attachmentModel : _attachmentModels) {
attachmentModel->addToScene(scene, transaction);
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
attachmentModel->setGroupCulled(true);
attachmentModel->setCanCastShadow(true);
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
attachmentRenderingNeedsUpdate = true;
}
if (attachmentRenderingNeedsUpdate) {
updateAttachmentRenderIDs();
}
_mustFadeIn = true;
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(getSessionUUID(), NestableType::Avatar, _skeletonModel);
@ -688,11 +673,6 @@ void Avatar::fadeOut(render::Transaction& transaction, KillAvatarReason reason)
void Avatar::fade(render::Transaction& transaction, render::Transition::Type type) {
transaction.resetTransitionOnItem(_renderItemID, type);
for (auto& attachmentModel : _attachmentModels) {
for (auto itemId : attachmentModel->fetchRenderItemIDs()) {
transaction.resetTransitionOnItem(itemId, type, _renderItemID);
}
}
_lastFadeRequested = type;
}
@ -704,9 +684,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe
transaction.removeItem(_renderItemID);
render::Item::clearID(_renderItemID);
_skeletonModel->removeFromScene(scene, transaction);
for (auto& attachmentModel : _attachmentModels) {
attachmentModel->removeFromScene(scene, transaction);
}
emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(getSessionUUID(), NestableType::Avatar, _skeletonModel);
}
@ -866,8 +843,6 @@ bool Avatar::getEnableMeshVisible() const {
void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
bool canTryFade{ false };
_attachmentsToDelete.clear();
// check to see if when we added our models to the scene they were ready, if they were not ready, then
// fix them up in the scene
render::Transaction transaction;
@ -885,27 +860,9 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
canTryFade = true;
_isAnimatingScale = true;
}
bool attachmentRenderingNeedsUpdate = false;
for (auto attachmentModel : _attachmentModels) {
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
attachmentModel->removeFromScene(scene, transaction);
attachmentModel->addToScene(scene, transaction);
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
attachmentModel->setGroupCulled(true);
attachmentModel->setCanCastShadow(true);
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
attachmentRenderingNeedsUpdate = true;
}
}
if (_needMeshVisibleSwitch) {
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
for (auto attachmentModel : _attachmentModels) {
if (attachmentModel->isRenderable()) {
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
}
}
updateRenderItem(transaction);
_needMeshVisibleSwitch = false;
}
@ -916,17 +873,6 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
_mustFadeIn = false;
}
for (auto attachmentModelToRemove : _attachmentsToRemove) {
attachmentModelToRemove->removeFromScene(scene, transaction);
attachmentRenderingNeedsUpdate = true;
}
_attachmentsToDelete.insert(_attachmentsToDelete.end(), _attachmentsToRemove.begin(), _attachmentsToRemove.end());
_attachmentsToRemove.clear();
if (attachmentRenderingNeedsUpdate) {
updateAttachmentRenderIDs();
}
scene->enqueueTransaction(transaction);
}
@ -934,48 +880,6 @@ bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const {
return true;
}
void Avatar::simulateAttachments(float deltaTime) {
assert(_attachmentModels.size() == _attachmentModelsTexturesLoaded.size());
PerformanceTimer perfTimer("attachments");
for (int i = 0; i < (int)_attachmentModels.size(); i++) {
const AttachmentData& attachment = _attachmentData.at(i);
auto& model = _attachmentModels.at(i);
bool texturesLoaded = _attachmentModelsTexturesLoaded.at(i);
// Watch for texture loading
if (!texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) {
_attachmentModelsTexturesLoaded[i] = true;
model->updateRenderItems();
}
int jointIndex = getJointIndex(attachment.jointName);
glm::vec3 jointPosition;
glm::quat jointRotation;
if (attachment.isSoft) {
// soft attachments do not have transform offsets
model->setTransformNoUpdateRenderItems(Transform(getWorldOrientation() * Quaternions::Y_180, glm::vec3(1.0), getWorldPosition()));
model->simulate(deltaTime);
model->updateRenderItems();
} else {
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) &&
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRotation)) {
model->setTransformNoUpdateRenderItems(Transform(jointRotation * attachment.rotation, glm::vec3(1.0), jointPosition + jointRotation * attachment.translation * getModelScale()));
float scale = getModelScale() * attachment.scale;
model->setScaleToFit(true, model->getNaturalDimensions() * scale, true); // hack to force rescale
model->setSnapModelToCenter(false); // hack to force resnap
model->setSnapModelToCenter(true);
model->simulate(deltaTime);
model->updateRenderItems();
}
}
}
if (_ancestorChainRenderableVersion != _lastAncestorChainRenderableVersion) {
_lastAncestorChainRenderableVersion = _ancestorChainRenderableVersion;
updateDescendantRenderIDs();
}
}
float Avatar::getBoundingRadius() const {
return getBounds().getLargestDimension() / 2.0f;
}
@ -1631,58 +1535,6 @@ void Avatar::updateFitBoundingBox() {
}
}
// create new model, can return an instance of a SoftAttachmentModel rather then Model
static std::shared_ptr<Model> allocateAttachmentModel(bool isSoft, const Rig& rigOverride, bool isCauterized) {
if (isSoft) {
// cast to std::shared_ptr<Model>
std::shared_ptr<SoftAttachmentModel> softModel = std::make_shared<SoftAttachmentModel>(nullptr, rigOverride);
if (isCauterized) {
softModel->flagAsCauterized();
}
return std::dynamic_pointer_cast<Model>(softModel);
} else {
return std::make_shared<Model>();
}
}
void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
Q_ARG(const QVector<AttachmentData>, attachmentData));
return;
}
auto oldAttachmentData = _attachmentData;
AvatarData::setAttachmentData(attachmentData);
// if number of attachments has been reduced, remove excess models.
while ((int)_attachmentModels.size() > attachmentData.size()) {
auto attachmentModel = _attachmentModels.back();
_attachmentModels.pop_back();
_attachmentModelsTexturesLoaded.pop_back();
_attachmentsToRemove.push_back(attachmentModel);
}
for (int i = 0; i < attachmentData.size(); i++) {
if (i == (int)_attachmentModels.size()) {
// if number of attachments has been increased, we need to allocate a new model
_attachmentModels.push_back(allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar()));
_attachmentModelsTexturesLoaded.push_back(false);
} else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) {
// if the attachment has changed type, we need to re-allocate a new one.
_attachmentsToRemove.push_back(_attachmentModels[i]);
_attachmentModels[i] = allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar());
_attachmentModelsTexturesLoaded[i] = false;
}
// If the model URL has changd, we need to wait for the textures to load
if (_attachmentModels[i]->getURL() != attachmentData[i].modelURL) {
_attachmentModelsTexturesLoaded[i] = false;
}
_attachmentModels[i]->setLoadingPriority(ATTACHMENT_LOADING_PRIORITY);
_attachmentModels[i]->setURL(attachmentData[i].modelURL);
}
}
int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
PerformanceTimer perfTimer("unpack");
if (!_initialized) {
@ -2102,11 +1954,6 @@ uint32_t Avatar::appendSubMetaItems(render::ItemIDs& subItems) {
return _subItemLock.resultWithReadLock<uint32_t>([&] {
uint32_t total = 0;
if (_attachmentRenderIDs.size() > 0) {
subItems.insert(subItems.end(), _attachmentRenderIDs.begin(), _attachmentRenderIDs.end());
total += (uint32_t)_attachmentRenderIDs.size();
}
if (_descendantRenderIDs.size() > 0) {
subItems.insert(subItems.end(), _descendantRenderIDs.begin(), _descendantRenderIDs.end());
total += (uint32_t)_descendantRenderIDs.size();
@ -2116,18 +1963,6 @@ uint32_t Avatar::appendSubMetaItems(render::ItemIDs& subItems) {
});
}
void Avatar::updateAttachmentRenderIDs() {
_subItemLock.withWriteLock([&] {
_attachmentRenderIDs.clear();
for (auto& attachmentModel : _attachmentModels) {
if (attachmentModel && attachmentModel->isRenderable()) {
auto& metaSubItems = attachmentModel->fetchRenderItemIDs();
_attachmentRenderIDs.insert(_attachmentRenderIDs.end(), metaSubItems.begin(), metaSubItems.end());
}
}
});
}
void Avatar::updateDescendantRenderIDs() {
_subItemLock.withWriteLock([&] {
auto oldRenderingDescendantEntityIDs = _renderingDescendantEntityIDs;

View file

@ -157,7 +157,6 @@ public:
void init();
void removeAvatarEntitiesFromTree();
virtual void simulate(float deltaTime, bool inView) = 0;
virtual void simulateAttachments(float deltaTime);
virtual void render(RenderArgs* renderArgs);
@ -344,7 +343,6 @@ public:
Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const;
Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override;
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
void updateDisplayNameAlpha(bool showDisplayName);
virtual void setSessionDisplayName(const QString& sessionDisplayName) override { }; // no-op
@ -650,10 +648,6 @@ protected:
mutable bool _modelJointsCached { false };
glm::vec3 _skeletonOffset;
std::vector<std::shared_ptr<Model>> _attachmentModels;
std::vector<bool> _attachmentModelsTexturesLoaded;
std::vector<std::shared_ptr<Model>> _attachmentsToRemove;
std::vector<std::shared_ptr<Model>> _attachmentsToDelete;
float _bodyYawDelta { 0.0f }; // degrees/sec
float _seatedBodyYawDelta{ 0.0f }; // degrees/renderframe
@ -753,7 +747,6 @@ protected:
static const float MYAVATAR_LOADING_PRIORITY;
static const float OTHERAVATAR_LOADING_PRIORITY;
static const float ATTACHMENT_LOADING_PRIORITY;
LoadingStatus _loadingStatus { LoadingStatus::NoModel };
@ -773,12 +766,9 @@ protected:
VectorOfIDs _grabsToDelete; // deleted grab IDs -- changes needed to entities or physics
ReadWriteLockable _subItemLock;
void updateAttachmentRenderIDs();
render::ItemIDs _attachmentRenderIDs;
void updateDescendantRenderIDs();
render::ItemIDs _descendantRenderIDs;
std::unordered_set<EntityItemID> _renderingDescendantEntityIDs;
uint32_t _lastAncestorChainRenderableVersion { 0 };
};
#endif // hifi_Avatar_h

View file

@ -58,8 +58,6 @@
* when the other avatar is in the line of sight and also has <code>lookAtSnappingEnabled == true</code>.
*
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @property {string[]} jointNames - The list of joints in the avatar model.
*
* @property {number} audioLoudness - The instantaneous loudness of the audio input that the avatar is injecting into the

View file

@ -73,17 +73,10 @@ static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water
STATIC_SCRIPT_TYPES_INITIALIZER((+[](ScriptManager* manager) {
auto scriptEngine = manager->engine().get();
registerAvatarTypes(scriptEngine);
scriptRegisterMetaType<RayToAvatarIntersectionResult, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue>(scriptEngine);
scriptRegisterMetaType<AvatarEntityMap, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue>(scriptEngine);
}));
STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) {
auto scriptEngine = manager->engine().get();
registerAvatarPrototypes(scriptEngine);
});
size_t AvatarDataPacket::maxFaceTrackerInfoSize(size_t numBlendshapeCoefficients) {
return FACE_TRACKER_INFO_SIZE + numBlendshapeCoefficients * sizeof(float);
}
@ -2027,7 +2020,6 @@ void AvatarData::processAvatarIdentity(QDataStream& packetStream, bool& identity
Identity identity;
packetStream
>> identity.attachmentData
>> identity.displayName
>> identity.sessionDisplayName
>> identity.identityFlags
@ -2068,11 +2060,6 @@ void AvatarData::processAvatarIdentity(QDataStream& packetStream, bool& identity
}
};
if (identity.attachmentData != _attachmentData) {
setAttachmentData(identity.attachmentData);
identityChanged = true;
}
#ifdef WANT_DEBUG
qCDebug(avatars) << __FUNCTION__
<< "identity.uuid:" << identity.uuid
@ -2319,7 +2306,6 @@ QByteArray AvatarData::identityByteArray(bool setIsReplicated) const {
identityStream << getSessionUUID()
<< (udt::SequenceNumber::Type) _identitySequenceNumber
<< _attachmentData
<< _displayName
<< getSessionDisplayNameForTransport() // depends on _sessionDisplayName
<< identityFlags;
@ -2353,86 +2339,6 @@ void AvatarData::setDisplayName(const QString& displayName) {
markIdentityDataChanged();
}
QVector<AttachmentData> AvatarData::getAttachmentData() const {
if (QThread::currentThread() != thread()) {
QVector<AttachmentData> result;
BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getAttachmentData",
Q_RETURN_ARG(QVector<AttachmentData>, result));
return result;
}
return _attachmentData;
}
void AvatarData::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAttachmentData", Q_ARG(const QVector<AttachmentData>&, attachmentData));
return;
}
_attachmentData = attachmentData;
markIdentityDataChanged();
}
void AvatarData::attach(const QString& modelURL, const QString& jointName,
const glm::vec3& translation, const glm::quat& rotation,
float scale, bool isSoft,
bool allowDuplicates, bool useSaved) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(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;
}
QVector<AttachmentData> attachmentData = getAttachmentData();
if (!allowDuplicates) {
foreach (const AttachmentData& data, attachmentData) {
if (data.modelURL == modelURL && (jointName.isEmpty() || data.jointName == jointName)) {
return;
}
}
}
AttachmentData data;
data.modelURL = modelURL;
data.jointName = jointName;
data.translation = translation;
data.rotation = rotation;
data.scale = scale;
data.isSoft = isSoft;
attachmentData.append(data);
setAttachmentData(attachmentData);
}
void AvatarData::detachOne(const QString& modelURL, const QString& jointName) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "detachOne", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName));
return;
}
QVector<AttachmentData> attachmentData = getAttachmentData();
for (QVector<AttachmentData>::iterator it = attachmentData.begin(); it != attachmentData.end(); ++it) {
if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) {
attachmentData.erase(it);
setAttachmentData(attachmentData);
return;
}
}
}
void AvatarData::detachAll(const QString& modelURL, const QString& jointName) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "detachAll", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName));
return;
}
QVector<AttachmentData> attachmentData = getAttachmentData();
for (QVector<AttachmentData>::iterator it = attachmentData.begin(); it != attachmentData.end(); ) {
if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) {
it = attachmentData.erase(it);
} else {
++it;
}
}
setAttachmentData(attachmentData);
}
int AvatarData::sendAvatarDataPacket(bool sendAll) {
auto nodeList = DependencyManager::get<NodeList>();
@ -2495,149 +2401,6 @@ int AvatarData::sendIdentityPacket() {
return identityData.size();
}
static const QString JSON_ATTACHMENT_URL = QStringLiteral("modelUrl");
static const QString JSON_ATTACHMENT_JOINT_NAME = QStringLiteral("jointName");
static const QString JSON_ATTACHMENT_TRANSFORM = QStringLiteral("transform");
static const QString JSON_ATTACHMENT_IS_SOFT = QStringLiteral("isSoft");
QJsonObject AttachmentData::toJson() const {
QJsonObject result;
if (modelURL.isValid() && !modelURL.isEmpty()) {
result[JSON_ATTACHMENT_URL] = modelURL.toString();
}
if (!jointName.isEmpty()) {
result[JSON_ATTACHMENT_JOINT_NAME] = jointName;
}
// FIXME the transform constructor that takes rot/scale/translation
// doesn't return the correct value for isIdentity()
Transform transform;
transform.setRotation(rotation);
transform.setScale(scale);
transform.setTranslation(translation);
if (!transform.isIdentity()) {
result[JSON_ATTACHMENT_TRANSFORM] = Transform::toJson(transform);
}
result[JSON_ATTACHMENT_IS_SOFT] = isSoft;
return result;
}
void AttachmentData::fromJson(const QJsonObject& json) {
if (json.contains(JSON_ATTACHMENT_URL)) {
const QString modelURLTemp = json[JSON_ATTACHMENT_URL].toString();
if (modelURLTemp != modelURL.toString()) {
modelURL = modelURLTemp;
}
}
if (json.contains(JSON_ATTACHMENT_JOINT_NAME)) {
const QString jointNameTemp = json[JSON_ATTACHMENT_JOINT_NAME].toString();
if (jointNameTemp != jointName) {
jointName = jointNameTemp;
}
}
if (json.contains(JSON_ATTACHMENT_TRANSFORM)) {
Transform transform = Transform::fromJson(json[JSON_ATTACHMENT_TRANSFORM]);
translation = transform.getTranslation();
rotation = transform.getRotation();
scale = transform.getScale().x;
}
if (json.contains(JSON_ATTACHMENT_IS_SOFT)) {
isSoft = json[JSON_ATTACHMENT_IS_SOFT].toBool();
}
}
bool AttachmentData::operator==(const AttachmentData& other) const {
return modelURL == other.modelURL && jointName == other.jointName && translation == other.translation &&
rotation == other.rotation && scale == other.scale && isSoft == other.isSoft;
}
QDataStream& operator<<(QDataStream& out, const AttachmentData& attachment) {
return out << attachment.modelURL << attachment.jointName <<
attachment.translation << attachment.rotation << attachment.scale << attachment.isSoft;
}
QDataStream& operator>>(QDataStream& in, AttachmentData& attachment) {
return in >> attachment.modelURL >> attachment.jointName >>
attachment.translation >> attachment.rotation >> attachment.scale >> attachment.isSoft;
}
void AttachmentDataObject::setModelURL(const QString& modelURL) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.modelURL = modelURL;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
QString AttachmentDataObject::getModelURL() const {
return scriptvalue_cast<AttachmentData>(thisObject()).modelURL.toString();
}
void AttachmentDataObject::setJointName(const QString& jointName) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.jointName = jointName;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
QString AttachmentDataObject::getJointName() const {
return scriptvalue_cast<AttachmentData>(thisObject()).jointName;
}
void AttachmentDataObject::setTranslation(const glm::vec3& translation) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.translation = translation;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
glm::vec3 AttachmentDataObject::getTranslation() const {
return scriptvalue_cast<AttachmentData>(thisObject()).translation;
}
void AttachmentDataObject::setRotation(const glm::quat& rotation) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.rotation = rotation;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
glm::quat AttachmentDataObject::getRotation() const {
return scriptvalue_cast<AttachmentData>(thisObject()).rotation;
}
void AttachmentDataObject::setScale(float scale) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.scale = scale;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
float AttachmentDataObject::getScale() const {
return scriptvalue_cast<AttachmentData>(thisObject()).scale;
}
void AttachmentDataObject::setIsSoft(bool isSoft) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.isSoft = isSoft;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
bool AttachmentDataObject::getIsSoft() const {
return scriptvalue_cast<AttachmentData>(thisObject()).isSoft;
}
void registerAvatarTypes(ScriptEngine* engine) {
scriptRegisterSequenceMetaType<QVector<AttachmentData> >(engine);
}
void registerAvatarPrototypes(ScriptEngine* engine) {
engine->setDefaultPrototype(qMetaTypeId<AttachmentData>(), engine->newQObject(
new AttachmentDataObject(), ScriptEngine::ScriptOwnership));
}
void AvatarData::setRecordingBasis(std::shared_ptr<Transform> recordingBasis) {
if (!recordingBasis) {
recordingBasis = std::make_shared<Transform>();
@ -2670,7 +2433,6 @@ static const QString JSON_AVATAR_HEAD_MODEL = QStringLiteral("headModel");
static const QString JSON_AVATAR_BODY_MODEL = QStringLiteral("bodyModel");
static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
// It isn't meaningful to persist sessionDisplayName.
static const QString JSON_AVATAR_ATTACHMENTS = QStringLiteral("attachments");
static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities");
static const QString JSON_AVATAR_SCALE = QStringLiteral("scale");
static const QString JSON_AVATAR_VERSION = QStringLiteral("version");
@ -2838,24 +2600,11 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) {
setTargetScale((float)json[JSON_AVATAR_SCALE].toDouble());
}
QVector<AttachmentData> attachments;
if (json.contains(JSON_AVATAR_ATTACHMENTS) && json[JSON_AVATAR_ATTACHMENTS].isArray()) {
QJsonArray attachmentsJson = json[JSON_AVATAR_ATTACHMENTS].toArray();
for (auto attachmentJson : attachmentsJson) {
AttachmentData attachment;
attachment.fromJson(attachmentJson.toObject());
attachments.push_back(attachment);
}
}
if (attachments != getAttachmentData()) {
setAttachmentData(attachments);
}
if (json.contains(JSON_AVATAR_ENTITIES) && json[JSON_AVATAR_ENTITIES].isArray()) {
QJsonArray attachmentsJson = json[JSON_AVATAR_ENTITIES].toArray();
for (auto attachmentJson : attachmentsJson) {
if (attachmentJson.isObject()) {
QVariantMap entityData = attachmentJson.toObject().toVariantMap();
QJsonArray avatarEntitiesJSON = json[JSON_AVATAR_ENTITIES].toArray();
for (auto avatarEntityJSON : avatarEntitiesJSON) {
if (avatarEntityJSON.isObject()) {
QVariantMap entityData = avatarEntityJSON.toObject().toVariantMap();
QUuid id = entityData.value("id").toUuid();
QByteArray data = QByteArray::fromBase64(entityData.value("properties").toByteArray());
updateAvatarEntity(id, data);
@ -2970,30 +2719,6 @@ glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const
return glm::vec3();
}
/*@jsdoc
* Information on an attachment worn by the avatar.
* @typedef {object} AttachmentData
* @property {string} modelUrl - The URL of the glTF, FBX, or OBJ model file. glTF models may be in JSON or binary format
* (".gltf" or ".glb" URLs respectively).
* @property {string} jointName - The name of the joint that the attachment is parented to.
* @property {Vec3} translation - The offset from the joint that the attachment is positioned at.
* @property {Vec3} rotation - The rotation applied to the model relative to the joint orientation.
* @property {number} scale - The scale applied to the attachment model.
* @property {boolean} soft - If <code>true</code> and the model has a skeleton, the bones of the attached model's skeleton are
* rotated to fit the avatar's current pose. If <code>true</code>, the <code>translation</code>, <code>rotation</code>, and
* <code>scale</code> parameters are ignored.
*/
QVariant AttachmentData::toVariant() const {
QVariantMap result;
result["modelUrl"] = modelURL;
result["jointName"] = jointName;
result["translation"] = vec3ToQMap(translation);
result["rotation"] = vec3ToQMap(glm::degrees(safeEulerAngles(rotation)));
result["scale"] = scale;
result["soft"] = isSoft;
return result;
}
glm::vec3 variantToVec3(const QVariant& var) {
auto map = var.toMap();
glm::vec3 result;
@ -3003,52 +2728,6 @@ glm::vec3 variantToVec3(const QVariant& var) {
return result;
}
bool AttachmentData::fromVariant(const QVariant& variant) {
bool isValid = false;
auto map = variant.toMap();
if (map.contains("modelUrl")) {
auto urlString = map["modelUrl"].toString();
modelURL = urlString;
isValid = true;
}
if (map.contains("jointName")) {
jointName = map["jointName"].toString();
}
if (map.contains("translation")) {
translation = variantToVec3(map["translation"]);
}
if (map.contains("rotation")) {
rotation = glm::quat(glm::radians(variantToVec3(map["rotation"])));
}
if (map.contains("scale")) {
scale = map["scale"].toFloat();
}
if (map.contains("soft")) {
isSoft = map["soft"].toBool();
}
return isValid;
}
QVariantList AvatarData::getAttachmentsVariant() const {
QVariantList result;
for (const auto& attachment : getAttachmentData()) {
result.append(attachment.toVariant());
}
return result;
}
void AvatarData::setAttachmentsVariant(const QVariantList& variant) {
QVector<AttachmentData> newAttachments;
newAttachments.reserve(variant.size());
for (const auto& attachmentVar : variant) {
AttachmentData attachment;
if (attachment.fromVariant(attachmentVar)) {
newAttachments.append(attachment);
}
}
setAttachmentData(newAttachments);
}
void AvatarData::storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& data) {
bool changed = false;
_avatarEntitiesLock.withWriteLock([&] {

View file

@ -451,7 +451,6 @@ Q_DECLARE_METATYPE(KillAvatarReason);
class QDataStream;
class AttachmentData;
class Transform;
using TransformPointer = std::shared_ptr<Transform>;
@ -523,8 +522,6 @@ class AvatarData : public QObject, public SpatiallyNestable {
* @property {boolean} lookAtSnappingEnabled=true - <code>true</code> if the avatar's eyes snap to look at another avatar's
* eyes when the other avatar is in the line of sight and also has <code>lookAtSnappingEnabled == true</code>.
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @property {string[]} jointNames - The list of joints in the current avatar model. <em>Read-only.</em>
* @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. <em>Read-only.</em>
* @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the
@ -580,7 +577,6 @@ class AvatarData : public QObject, public SpatiallyNestable {
Q_PROPERTY(QString sessionDisplayName READ getSessionDisplayName WRITE setSessionDisplayName NOTIFY sessionDisplayNameChanged)
Q_PROPERTY(bool lookAtSnappingEnabled MEMBER _lookAtSnappingEnabled NOTIFY lookAtSnappingChanged)
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript NOTIFY skeletonModelURLChanged)
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData WRITE setAttachmentData)
Q_PROPERTY(QStringList jointNames READ getJointNames)
@ -1145,27 +1141,6 @@ public:
*/
Q_INVOKABLE void setBlendshape(QString name, float val) { _headData->setBlendshape(name, val); }
/*@jsdoc
* Gets information about the models currently attached to your avatar.
* @function Avatar.getAttachmentsVariant
* @returns {AttachmentData[]} Information about all models attached to your avatar.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
*/
// FIXME: Can this name be improved? Can it be deprecated?
Q_INVOKABLE virtual QVariantList getAttachmentsVariant() const;
/*@jsdoc
* Sets all models currently attached to your avatar. For example, if you retrieve attachment data using
* {@link MyAvatar.getAttachmentsVariant} or {@link Avatar.getAttachmentsVariant}, make changes to it, and then want to
* update your avatar's attachments per the changed data.
* @function Avatar.setAttachmentsVariant
* @param {AttachmentData[]} variant - The attachment data defining the models to have attached to your avatar.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
*/
// FIXME: Can this name be improved? Can it be deprecated?
Q_INVOKABLE virtual void setAttachmentsVariant(const QVariantList& variant);
virtual void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload);
/*@jsdoc
@ -1209,7 +1184,6 @@ public:
const HeadData* getHeadData() const { return _headData; }
struct Identity {
QVector<AttachmentData> attachmentData;
QString displayName;
QString sessionDisplayName;
bool isReplicated;
@ -1254,109 +1228,6 @@ public:
}
virtual bool isCertifyFailed() const { return _verificationFailed; }
/*@jsdoc
* Gets information about the models currently attached to your avatar.
* @function Avatar.getAttachmentData
* @returns {AttachmentData[]} Information about all models attached to your avatar.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
* @example <caption>Report the URLs of all current attachments.</caption>
* var attachments = MyAvatar.getaAttachmentData();
* for (var i = 0; i < attachments.length; i++) {
* print(attachments[i].modelURL);
* }
*
* // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual QVector<AttachmentData> getAttachmentData() const;
/*@jsdoc
* Sets all models currently attached to your avatar. For example, if you retrieve attachment data using
* {@link MyAvatar.getAttachmentData} or {@link Avatar.getAttachmentData}, make changes to it, and then want to update your avatar's attachments per the
* changed data. You can also remove all attachments by using setting <code>attachmentData</code> to <code>null</code>.
* @function Avatar.setAttachmentData
* @param {AttachmentData[]} attachmentData - The attachment data defining the models to have attached to your avatar. Use
* <code>null</code> to remove all attachments.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
* @example <caption>Remove a hat attachment if your avatar is wearing it.</caption>
* var hatURL = "https://apidocs.overte.org/examples/cowboy-hat.fbx";
* var attachments = MyAvatar.getAttachmentData();
*
* for (var i = 0; i < attachments.length; i++) {
* if (attachments[i].modelURL === hatURL) {
* attachments.splice(i, 1);
* MyAvatar.setAttachmentData(attachments);
* break;
* }
* }
*
* // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar".
*/
Q_INVOKABLE virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
/*@jsdoc
* Attaches a model to your avatar. For example, you can give your avatar a hat to wear, a guitar to hold, or a surfboard to
* stand on.
* @function Avatar.attach
* @param {string} modelURL - The URL of the glTF, FBX, or OBJ model to attach. glTF models may be in JSON or binary format
* (".gltf" or ".glb" URLs respectively).
* @param {string} [jointName=""] - The name of the avatar joint (see {@link MyAvatar.getJointNames} or
* {@link Avatar.getJointNames}) to attach the model to.
* @param {Vec3} [translation=Vec3.ZERO] - The offset to apply to the model relative to the joint position.
* @param {Quat} [rotation=Quat.IDENTITY] - The rotation to apply to the model relative to the joint orientation.
* @param {number} [scale=1.0] - The scale to apply to the model.
* @param {boolean} [isSoft=false] - If the model has a skeleton, set this to <code>true</code> so that the bones of the
* attached model's skeleton are rotated to fit the avatar's current pose. <code>isSoft</code> is used, for example,
* to have clothing that moves with the avatar.
* <p>If <code>true</code>, the <code>translation</code>, <code>rotation</code>, and <code>scale</code> parameters are
* ignored.</p>
* @param {boolean} [allowDuplicates=false] - If <code>true</code> then more than one copy of any particular model may be
* attached to the same joint; if <code>false</code> then the same model cannot be attached to the same joint.
* @param {boolean} [useSaved=true] - <em>Not used.</em>
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
* @example <caption>Attach a cowboy hat to your avatar's head.</caption>
* var attachment = {
* modelURL: "https://apidocs.overte.org/examples/cowboy-hat.fbx",
* jointName: "Head",
* translation: {"x": 0, "y": 0.25, "z": 0},
* rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
* scale: 0.01,
* isSoft: false
* };
*
* MyAvatar.attach(attachment.modelURL,
* attachment.jointName,
* attachment.translation,
* attachment.rotation,
* attachment.scale,
* attachment.isSoft);
*
* // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar".
*/
Q_INVOKABLE 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);
/*@jsdoc
* Detaches the most recently attached instance of a particular model from either a specific joint or any joint.
* @function Avatar.detachOne
* @param {string} modelURL - The URL of the model to detach.
* @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.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
*/
Q_INVOKABLE virtual void detachOne(const QString& modelURL, const QString& jointName = QString());
/*@jsdoc
* Detaches all instances of a particular model from either a specific joint or all joints.
* @function Avatar.detachAll
* @param {string} modelURL - The URL of the model to detach.
* @param {string} [jointName=""] - The name of the joint to detach the model from. If <code>""</code>, then the model is
* detached from all joints.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
*/
Q_INVOKABLE virtual void detachAll(const QString& modelURL, const QString& jointName = QString());
QString getSkeletonModelURLFromScript() const;
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
@ -1732,8 +1603,6 @@ protected:
mutable HeadData* _headData { nullptr };
QUrl _skeletonModelURL;
QVector<AttachmentData> _attachmentData;
QVector<AttachmentData> _oldAttachmentData;
QString _displayName;
QString _sessionDisplayName { };
bool _lookAtSnappingEnabled { true };
@ -1899,66 +1768,6 @@ Q_DECLARE_METATYPE(AvatarData*)
QJsonValue toJsonValue(const JointData& joint);
JointData jointDataFromJsonValue(const QJsonValue& q);
class AttachmentData {
public:
QUrl modelURL;
QString jointName;
glm::vec3 translation;
glm::quat rotation;
float scale { 1.0f };
bool isSoft { false };
bool isValid() const { return modelURL.isValid(); }
bool operator==(const AttachmentData& other) const;
QJsonObject toJson() const;
void fromJson(const QJsonObject& json);
QVariant toVariant() const;
bool fromVariant(const QVariant& variant);
};
QDataStream& operator<<(QDataStream& out, const AttachmentData& attachment);
QDataStream& operator>>(QDataStream& in, AttachmentData& attachment);
Q_DECLARE_METATYPE(AttachmentData)
Q_DECLARE_METATYPE(QVector<AttachmentData>)
/// Scriptable wrapper for attachments.
class AttachmentDataObject : public QObject, protected Scriptable {
Q_OBJECT
Q_PROPERTY(QString modelURL READ getModelURL WRITE setModelURL)
Q_PROPERTY(QString jointName READ getJointName WRITE setJointName)
Q_PROPERTY(glm::vec3 translation READ getTranslation WRITE setTranslation)
Q_PROPERTY(glm::quat rotation READ getRotation WRITE setRotation)
Q_PROPERTY(float scale READ getScale WRITE setScale)
Q_PROPERTY(bool isSoft READ getIsSoft WRITE setIsSoft)
public:
Q_INVOKABLE void setModelURL(const QString& modelURL);
Q_INVOKABLE QString getModelURL() const;
Q_INVOKABLE void setJointName(const QString& jointName);
Q_INVOKABLE QString getJointName() const;
Q_INVOKABLE void setTranslation(const glm::vec3& translation);
Q_INVOKABLE glm::vec3 getTranslation() const;
Q_INVOKABLE void setRotation(const glm::quat& rotation);
Q_INVOKABLE glm::quat getRotation() const;
Q_INVOKABLE void setScale(float scale);
Q_INVOKABLE float getScale() const;
Q_INVOKABLE void setIsSoft(bool scale);
Q_INVOKABLE bool getIsSoft() const;
};
void registerAvatarTypes(ScriptEngine* engine);
void registerAvatarPrototypes(ScriptEngine* engine);
class RayToAvatarIntersectionResult {
public:
bool intersects { false };

View file

@ -200,7 +200,7 @@ bool ScriptAvatarData::getLookAtSnappingEnabled() const {
//
//
// ATTACHMENT AND JOINT PROPERTIES
// JOINT PROPERTIES
// START
//
QString ScriptAvatarData::getSkeletonModelURLFromScript() const {
@ -285,15 +285,8 @@ QStringList ScriptAvatarData::getJointNames() const {
return QStringList();
}
}
QVector<AttachmentData> ScriptAvatarData::getAttachmentData() const {
if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) {
return sharedAvatarData->getAttachmentData();
} else {
return QVector<AttachmentData>();
}
}
//
// ATTACHMENT AND JOINT PROPERTIES
// JOINT PROPERTIES
// END
//

View file

@ -50,10 +50,9 @@ class ScriptAvatarData : public QObject {
Q_PROPERTY(bool lookAtSnappingEnabled READ getLookAtSnappingEnabled NOTIFY lookAtSnappingChanged)
//
// ATTACHMENT AND JOINT PROPERTIES
// JOINT PROPERTIES
//
Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript NOTIFY skeletonModelURLChanged)
Q_PROPERTY(QVector<AttachmentData> attachmentData READ getAttachmentData)
Q_PROPERTY(QStringList jointNames READ getJointNames)
//
@ -104,7 +103,7 @@ public:
bool getLookAtSnappingEnabled() const;
//
// ATTACHMENT AND JOINT PROPERTIES
// JOINT PROPERTIES
//
QString getSkeletonModelURLFromScript() const;
@ -204,15 +203,6 @@ public:
*/
Q_INVOKABLE QStringList getJointNames() const;
/*@jsdoc
* Gets information about the models currently attached to the avatar.
* @function ScriptAvatar.getAttachmentData
* @returns {AttachmentData[]} Information about all models attached to the avatar, or <code>[]</code> if the avatar data
* aren't available.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
*/
Q_INVOKABLE QVector<AttachmentData> getAttachmentData() const;
#if DEV_BUILD || PR_BUILD
Q_INVOKABLE AvatarEntityMap getAvatarEntities() const;
#endif

View file

@ -454,7 +454,6 @@ bool EntityRenderer::addToScene(const ScenePointer& scene, Transaction& transact
transaction.resetItem(_renderItemID, renderPayload);
onAddToScene(_entity);
updateInScene(scene, transaction);
_entity->bumpAncestorChainRenderableVersion();
return true;
}
@ -462,7 +461,6 @@ void EntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& tra
onRemoveFromScene(_entity);
transaction.removeItem(_renderItemID);
Item::clearID(_renderItemID);
_entity->bumpAncestorChainRenderableVersion();
}
void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& transaction) {

View file

@ -1261,7 +1261,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
if (!_hasModel) {
if (model) {
model->removeFromScene(scene, transaction);
entity->bumpAncestorChainRenderableVersion();
emit DependencyManager::get<scriptable::ModelProviderFactory>()->
modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, model);
withWriteLock([&] { _model.reset(); });
@ -1391,7 +1390,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
makeStatusGetters(entity, statusGetters);
using namespace std::placeholders;
model->addToScene(scene, transaction, statusGetters, std::bind(&ModelEntityRenderer::metaBlendshapeOperator, _renderItemID, _1, _2, _3, _4));
entity->bumpAncestorChainRenderableVersion();
processMaterials();
}
}

View file

@ -2969,10 +2969,6 @@ void EntityItem::setVisible(bool value) {
_needsRenderUpdate |= changed;
_visible = value;
});
if (changed) {
bumpAncestorChainRenderableVersion();
}
}
bool EntityItem::isVisibleInSecondaryCamera() const {

View file

@ -183,7 +183,6 @@ QString FSTReader::getNameFromType(ModelType modelType) {
_typesToNames[HEAD_MODEL] = "head";
_typesToNames[BODY_ONLY_MODEL] = "body";
_typesToNames[HEAD_AND_BODY_MODEL] = "body+head";
_typesToNames[ATTACHMENT_MODEL] = "attachment";
}
return _typesToNames[modelType];
}
@ -195,9 +194,6 @@ FSTReader::ModelType FSTReader::getTypeFromName(const QString& name) {
_namesToTypes["head"] = HEAD_MODEL ;
_namesToTypes["body"] = BODY_ONLY_MODEL;
_namesToTypes["body+head"] = HEAD_AND_BODY_MODEL;
// NOTE: this is not yet implemented, but will be used to allow you to attach fully independent models to your avatar
_namesToTypes["attachment"] = ATTACHMENT_MODEL;
}
return _namesToTypes[name];
}

View file

@ -42,8 +42,7 @@ public:
ENTITY_MODEL,
HEAD_MODEL,
BODY_ONLY_MODEL,
HEAD_AND_BODY_MODEL,
ATTACHMENT_MODEL
HEAD_AND_BODY_MODEL
};
/// Reads an FST mapping from the supplied data.

View file

@ -38,10 +38,10 @@ PacketVersion versionForPacketType(PacketType packetType) {
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
case PacketType::AvatarIdentity:
case PacketType::AvatarData:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::ARKitBlendshapes);
return static_cast<PacketVersion>(AvatarMixerPacketVersion::RemoveAttachments);
case PacketType::BulkAvatarData:
case PacketType::KillAvatar:
return static_cast<PacketVersion>(AvatarMixerPacketVersion::ARKitBlendshapes);
return static_cast<PacketVersion>(AvatarMixerPacketVersion::RemoveAttachments);
case PacketType::MessagesData:
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
// ICE packets

View file

@ -363,7 +363,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
FBXJointOrderChange,
HandControllerSection,
SendVerificationFailed,
ARKitBlendshapes
ARKitBlendshapes,
RemoveAttachments,
};
enum class DomainConnectRequestVersion : PacketVersion {

View file

@ -172,10 +172,6 @@ void RecordingScriptingInterface::setPlayerUseDisplayName(bool useDisplayName) {
_useDisplayName = useDisplayName;
}
void RecordingScriptingInterface::setPlayerUseAttachments(bool useAttachments) {
_useAttachments = useAttachments;
}
void RecordingScriptingInterface::setPlayerUseHeadModel(bool useHeadModel) {
_useHeadModel = useHeadModel;
}

View file

@ -162,14 +162,6 @@ public slots:
*/
void setPlayerUseDisplayName(bool useDisplayName);
/*@jsdoc
* <p><em>Not used.</em></p>
* @function Recording.setPlayerUseAttachments
* @param {boolean} useAttachments - Use attachments.
* @deprecated This method is deprecated and will be removed.
*/
void setPlayerUseAttachments(bool useAttachments);
/*@jsdoc
* <p><em>Not used.</em></p>
* @function Recording.setPlayerUseHeadModel
@ -203,14 +195,6 @@ public slots:
*/
bool getPlayerUseDisplayName() { return _useDisplayName; }
/*@jsdoc
* <p><em>Not used.</em></p>
* @function Recording.getPlayerUseAttachments
* @returns {boolean} Use attachments.
* @deprecated This method is deprecated and will be removed.
*/
bool getPlayerUseAttachments() { return _useAttachments; }
/*@jsdoc
* <p><em>Not used.</em></p>
* @function Recording.getPlayerUseHeadModel
@ -365,7 +349,6 @@ protected:
Flag _playFromCurrentLocation { true };
Flag _useDisplayName { false };
Flag _useHeadModel { false };
Flag _useAttachments { false };
Flag _useSkeletonModel { false };
recording::ClipPointer _lastClip;

View file

@ -1,73 +0,0 @@
//
// Created by Anthony J. Thibault on 12/17/15.
// Copyright 2013 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 "SoftAttachmentModel.h"
SoftAttachmentModel::SoftAttachmentModel(QObject* parent, const Rig& rigOverride) :
CauterizedModel(parent),
_rigOverride(rigOverride) {
}
SoftAttachmentModel::~SoftAttachmentModel() {
}
// virtual
void SoftAttachmentModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
_needsUpdateClusterMatrices = true;
}
int SoftAttachmentModel::getJointIndexOverride(int i) const {
QString name = _rig.nameOfJoint(i);
if (name.isEmpty()) {
return -1;
}
return _rigOverride.indexOfJoint(name);
}
// virtual
// use the _rigOverride matrices instead of the Model::_rig
void SoftAttachmentModel::updateClusterMatrices() {
if (!_needsUpdateClusterMatrices) {
return;
}
if (!isLoaded()) {
return;
}
_needsUpdateClusterMatrices = false;
const HFMModel& hfmModel = getHFMModel();
for (int i = 0; i < (int) _meshStates.size(); i++) {
MeshState& state = _meshStates[i];
const HFMMesh& mesh = hfmModel.meshes.at(i);
int meshIndex = i;
for (int j = 0; j < mesh.clusters.size(); j++) {
const HFMCluster& cluster = mesh.clusters.at(j);
int clusterIndex = j;
// TODO: cache these look-ups as an optimization
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
}
if (_useDualQuaternionSkinning) {
glm::mat4 m;
glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, m);
state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(m);
} else {
glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]);
}
}
}
updateBlendshapes();
}

View file

@ -1,38 +0,0 @@
//
// Created by Anthony J. Thibault on 12/17/15.
// Copyright 2015 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_SoftAttachmentModel_h
#define hifi_SoftAttachmentModel_h
#include "CauterizedModel.h"
// A model that allows the creator to specify a secondary rig instance.
// When the cluster matrices are created for rendering, the
// cluster matrices will use the secondary rig for the joint poses
// instead of the primary rig.
//
// This is used by Avatar instances to wear clothing that follows the same
// animated pose as the SkeletonModel.
class SoftAttachmentModel : public CauterizedModel {
Q_OBJECT
public:
SoftAttachmentModel(QObject* parent, const Rig& rigOverride);
~SoftAttachmentModel();
void updateRig(float deltaTime, glm::mat4 parentTransform) override;
void updateClusterMatrices() override;
protected:
int getJointIndexOverride(int i) const;
const Rig& _rigOverride;
};
#endif // hifi_SoftAttachmentModel_h

View file

@ -69,7 +69,6 @@ const QUuid SpatiallyNestable::getParentID() const {
}
void SpatiallyNestable::setParentID(const QUuid& parentID) {
bumpAncestorChainRenderableVersion();
bool success = false;
auto parent = getParentPointer(success);
bool parentChanged = false;
@ -89,7 +88,6 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) {
success = false;
parent = getParentPointer(success);
if (success && parent) {
bumpAncestorChainRenderableVersion();
parent->updateQueryAACube();
parent->recalculateChildCauterization();
}
@ -1509,17 +1507,3 @@ QUuid SpatiallyNestable::getEditSenderID() {
});
return editSenderID;
}
void SpatiallyNestable::bumpAncestorChainRenderableVersion(int depth) const {
if (depth > MAX_PARENTING_CHAIN_SIZE) {
// can't break the parent chain here, because it will call setParentID, which calls this
return;
}
_ancestorChainRenderableVersion++;
bool success = false;
auto parent = getParentPointer(success);
if (success && parent) {
parent->bumpAncestorChainRenderableVersion(depth + 1);
}
}

View file

@ -224,8 +224,6 @@ public:
bool hasGrabs();
virtual QUuid getEditSenderID();
void bumpAncestorChainRenderableVersion(int depth = 0) const;
protected:
QUuid _id;
mutable SpatiallyNestableWeakPointer _parent;
@ -248,8 +246,6 @@ protected:
mutable ReadWriteLockable _grabsLock;
QSet<GrabPointer> _grabs; // upon this thing
mutable std::atomic<uint32_t> _ancestorChainRenderableVersion { 0 };
private:
SpatiallyNestable() = delete;
const NestableType _nestableType; // EntityItem or an AvatarData