mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 07:12:40 +02:00
remove attachments
This commit is contained in:
parent
54d70a5679
commit
55907acd70
30 changed files with 19 additions and 1313 deletions
|
@ -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
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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([&] {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2969,10 +2969,6 @@ void EntityItem::setVisible(bool value) {
|
|||
_needsRenderUpdate |= changed;
|
||||
_visible = value;
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
bumpAncestorChainRenderableVersion();
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityItem::isVisibleInSecondaryCamera() const {
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -363,7 +363,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
|||
FBXJointOrderChange,
|
||||
HandControllerSection,
|
||||
SendVerificationFailed,
|
||||
ARKitBlendshapes
|
||||
ARKitBlendshapes,
|
||||
RemoveAttachments,
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue