//// ModelEntityItem.cpp// libraries/entities/src//// Created by Brad Hefta-Gaub on 12/4/13.// 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 "ModelEntityItem.h" #include <QtCore/QJsonDocument> #include <glm/gtx/transform.hpp> #include <ByteCountCoding.h>#include <GLMHelpers.h> #include "EntitiesLogging.h"#include "EntityItemProperties.h"#include "EntityTree.h"#include "EntityTreeElement.h"#include "ResourceCache.h" const QString ModelEntityItem::DEFAULT_MODEL_URL = QString("");const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString(""); EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { std::shared_ptr<ModelEntityItem> entity(new ModelEntityItem(entityID), [](ModelEntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); return entity;} ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _blendshapeCoefficientsVector((int)Blendshapes::BlendshapeCount, 0.0f), _lastAnimated(usecTimestampNow()){ _type = EntityTypes::Model; _visuallyReady = false;} EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class @Model_ENTITY_COPY_TO@ return properties;} bool ModelEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; @Model_ENTITY_SET_FROM@ withWriteLock([&] { AnimationPropertyGroup animationProperties = _animationProperties; animationProperties.setProperties(properties); bool somethingChangedInAnimations = applyNewAnimationProperties(animationProperties); somethingChanged = somethingChanged || somethingChangedInAnimations; }); return somethingChanged;} EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); @Model_REQUESTED_PROPS@ return requestedProperties;} void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertiesDidntFit, int& propertyCount, OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; @Model_ENTITY_APPEND@ } int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) { int bytesRead = 0; const unsigned char* dataAt = data; bool animationPropertiesChanged = false; @Model_ENTITY_READ@ // grab a local copy of _animationProperties to avoid multiple locks int bytesFromAnimation; AnimationPropertyGroup animationProperties; withReadLock([&] { animationProperties = _animationProperties; bytesFromAnimation = animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, animationPropertiesChanged); }); if (animationPropertiesChanged) { withWriteLock([&] { applyNewAnimationProperties(animationProperties); }); somethingChanged = true; } bytesRead += bytesFromAnimation; dataAt += bytesFromAnimation; return bytesRead;} // added update function back for property fixvoid ModelEntityItem::update(const quint64& now) { assert(_lastAnimated > 0); // increment timestamp before checking "hold" auto interval = now - _lastAnimated; _lastAnimated = now; // grab a local copy of _animationProperties to avoid multiple locks auto animationProperties = getAnimationProperties(); // bail on "hold" if (animationProperties.getHold()) { return; } // increment animation frame _currentFrame += (animationProperties.getFps() * ((float)interval) / (float)USECS_PER_SECOND); if (_currentFrame > animationProperties.getLastFrame() + 1.0f) { if (animationProperties.getLoop()) { _currentFrame = animationProperties.computeLoopedFrame(_currentFrame); } else { _currentFrame = animationProperties.getLastFrame(); } } else if (_currentFrame < animationProperties.getFirstFrame()) { if (animationProperties.getFirstFrame() < 0.0f) { _currentFrame = 0.0f; } else { _currentFrame = animationProperties.getFirstFrame(); } } setAnimationCurrentFrame(_currentFrame); EntityItem::update(now);} void ModelEntityItem::debugDump() const { qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " name:" << _name; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); qCDebug(entities) << " pointer:" << this; @Model_ENTITY_DEBUG@ } void ModelEntityItem::setShapeType(ShapeType type) { bool changed = false; uint32_t flags = 0; withWriteLock([&] { if (type != _shapeType) { if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) { // dynamic and STATIC_MESH are incompatible // since the shape is being set here we clear the dynamic bit _dynamic = false; flags = Simulation::DIRTY_MOTION_TYPE; } _shapeType = type; flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; changed = true; } }); if (changed) { markDirtyFlags(flags); locationChanged(); }} ShapeType ModelEntityItem::getShapeType() const { ShapeType type = resultWithReadLock<ShapeType>([&] { return _shapeType; }); if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) { // dynamic is incompatible with STATIC_MESH // shouldn't fall in here but just in case --> fall back to COMPOUND type = SHAPE_TYPE_COMPOUND; } if (type == SHAPE_TYPE_COMPOUND && !hasCompoundShapeURL()) { // no compoundURL set --> fall back to SIMPLE_COMPOUND type = SHAPE_TYPE_SIMPLE_COMPOUND; } return type;} glm::vec3 ModelEntityItem::getScaledDimensions() const { glm::vec3 parentScale = getTransform().getScale(); return _unscaledDimensions * parentScale;} void ModelEntityItem::setScaledDimensions(const glm::vec3& value) { glm::vec3 parentScale = getTransform().getScale(); setUnscaledDimensions(value / parentScale);} const Transform ModelEntityItem::getTransform() const { bool success; return getTransform(success);} const Transform ModelEntityItem::getTransform(bool& success, int depth) const { const Transform parentTransform = getParentTransform(success, depth); Transform localTransform = getLocalTransform(); localTransform.postScale(getModelScale()); Transform worldTransform; Transform::mult(worldTransform, parentTransform, localTransform); return worldTransform;} const Transform ModelEntityItem::getTransformWithOnlyLocalRotation(bool& success, int depth) const { const Transform parentTransform = getParentTransform(success, depth); Transform localTransform = getLocalTransform(); localTransform.postScale(getModelScale()); Transform worldTransform; Transform::mult(worldTransform, parentTransform, localTransform); worldTransform.setRotation(localTransform.getRotation()); return worldTransform;} void ModelEntityItem::setAnimationSettings(const QString& value) { // NOTE: this method only called for old bitstream format AnimationPropertyGroup animationProperties; withReadLock([&] { animationProperties = _animationProperties; }); // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, currentFrame, or running, those values will be parsed out and // will over ride the regular animation settings QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); if (settingsMap.contains("fps")) { float fps = settingsMap["fps"].toFloat(); animationProperties.setFps(fps); } // old settings used frameIndex if (settingsMap.contains("frameIndex")) { float currentFrame = settingsMap["frameIndex"].toFloat(); animationProperties.setCurrentFrame(currentFrame); } if (settingsMap.contains("running")) { bool running = settingsMap["running"].toBool(); if (running != animationProperties.getRunning()) { animationProperties.setRunning(running); } } if (settingsMap.contains("firstFrame")) { float firstFrame = settingsMap["firstFrame"].toFloat(); animationProperties.setFirstFrame(firstFrame); } if (settingsMap.contains("lastFrame")) { float lastFrame = settingsMap["lastFrame"].toFloat(); animationProperties.setLastFrame(lastFrame); } if (settingsMap.contains("loop")) { bool loop = settingsMap["loop"].toBool(); animationProperties.setLoop(loop); } if (settingsMap.contains("hold")) { bool hold = settingsMap["hold"].toBool(); animationProperties.setHold(hold); } if (settingsMap.contains("allowTranslation")) { bool allowTranslation = settingsMap["allowTranslation"].toBool(); animationProperties.setAllowTranslation(allowTranslation); } withWriteLock([&] { applyNewAnimationProperties(animationProperties); });} QString ModelEntityItem::getModelURL() const { return resultWithReadLock<QString>([&] { return _modelURL; });} void ModelEntityItem::setModelURL(const QString& value) { withWriteLock([&] { _needsRenderUpdate |= _modelURL != value; _modelURL = value; });} void ModelEntityItem::resizeJointArrays(int newSize) { if (newSize < 0) { return; } _jointDataLock.withWriteLock([&] { if (newSize > _localJointData.size()) { _localJointData.resize(newSize); } });} void ModelEntityItem::setAnimationJointsData(const QVector<EntityJointData>& jointsData) { resizeJointArrays(jointsData.size()); _jointDataLock.withWriteLock([&] { for (auto index = 0; index < jointsData.size(); ++index) { const auto& newJointData = jointsData[index]; auto& localJointData = _localJointData[index]; if (newJointData.translationSet) { localJointData.joint.translation = newJointData.translation; localJointData.translationDirty = true; } if (newJointData.rotationSet) { localJointData.joint.rotation = newJointData.rotation; localJointData.rotationDirty = true; } } });} void ModelEntityItem::setJointRotations(const QVector<glm::quat>& rotations) { resizeJointArrays(rotations.size()); _jointDataLock.withWriteLock([&] { _jointRotationsExplicitlySet = rotations.size() > 0; for (int index = 0; index < rotations.size(); index++) { auto& jointData = _localJointData[index]; if (jointData.joint.rotationSet) { jointData.joint.rotation = rotations[index]; jointData.rotationDirty = true; } } });} void ModelEntityItem::setJointRotationsSet(const QVector<bool>& rotationsSet) { resizeJointArrays(rotationsSet.size()); _jointDataLock.withWriteLock([&] { _jointRotationsExplicitlySet = rotationsSet.size() > 0; for (int index = 0; index < rotationsSet.size(); index++) { _localJointData[index].joint.rotationSet = rotationsSet[index]; } });} void ModelEntityItem::setJointTranslations(const QVector<glm::vec3>& translations) { resizeJointArrays(translations.size()); _jointDataLock.withWriteLock([&] { _jointTranslationsExplicitlySet = translations.size() > 0; for (int index = 0; index < translations.size(); index++) { auto& jointData = _localJointData[index]; if (jointData.joint.translationSet) { jointData.joint.translation = translations[index]; jointData.translationDirty = true; } } });} void ModelEntityItem::setJointTranslationsSet(const QVector<bool>& translationsSet) { resizeJointArrays(translationsSet.size()); _jointDataLock.withWriteLock([&] { _jointTranslationsExplicitlySet = translationsSet.size() > 0; for (int index = 0; index < translationsSet.size(); index++) { _localJointData[index].joint.translationSet = translationsSet[index]; } });} QVector<glm::quat> ModelEntityItem::getJointRotations() const { QVector<glm::quat> result; _jointDataLock.withReadLock([&] { if (_jointRotationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.rotation; } } }); return result;} QVector<bool> ModelEntityItem::getJointRotationsSet() const { QVector<bool> result; _jointDataLock.withReadLock([&] { if (_jointRotationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.rotationSet; } } }); return result;} QVector<glm::vec3> ModelEntityItem::getJointTranslations() const { QVector<glm::vec3> result; _jointDataLock.withReadLock([&] { if (_jointTranslationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.translation; } } }); return result;} QVector<bool> ModelEntityItem::getJointTranslationsSet() const { QVector<bool> result; _jointDataLock.withReadLock([&] { if (_jointTranslationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.translationSet; } } }); return result;} bool ModelEntityItem::hasModel() const { return resultWithReadLock<bool>([&] { return !_modelURL.isEmpty(); });}bool ModelEntityItem::hasCompoundShapeURL() const { return resultWithReadLock<bool>([&] { return !_compoundShapeURL.isEmpty(); });} QString ModelEntityItem::getCompoundShapeURL() const { return resultWithReadLock<QString>([&] { return _compoundShapeURL; });} void ModelEntityItem::setCompoundShapeURL(const QString& url) { withWriteLock([&] { _compoundShapeURL = url; });} // Animation related items...AnimationPropertyGroup ModelEntityItem::getAnimationProperties() const { return resultWithReadLock<AnimationPropertyGroup>([&] { return _animationProperties; });} bool ModelEntityItem::hasAnimation() const { return resultWithReadLock<bool>([&] { return !_animationProperties.getUrl().isEmpty(); });} QString ModelEntityItem::getAnimationURL() const { return resultWithReadLock<QString>([&] { return _animationProperties.getUrl(); });} void ModelEntityItem::setAnimationCurrentFrame(float value) { withWriteLock([&] { _animationProperties.setCurrentFrame(value); });} bool ModelEntityItem::getAnimationAllowTranslation() const { return resultWithReadLock<bool>([&] { return _animationProperties.getAllowTranslation();Lines 1–500 of 630. Load more
// // ModelEntityItem.cpp // libraries/entities/src // // Created by Brad Hefta-Gaub on 12/4/13. // 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 "ModelEntityItem.h" #include <QtCore/QJsonDocument> #include <glm/gtx/transform.hpp> #include <ByteCountCoding.h> #include <GLMHelpers.h> #include "EntitiesLogging.h" #include "EntityItemProperties.h" #include "EntityTree.h" #include "EntityTreeElement.h" #include "ResourceCache.h" const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString(""); EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { std::shared_ptr<ModelEntityItem> entity(new ModelEntityItem(entityID), [](ModelEntityItem* ptr) { ptr->deleteLater(); }); entity->setProperties(properties); return entity; } ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _blendshapeCoefficientsVector((int)Blendshapes::BlendshapeCount, 0.0f), _lastAnimated(usecTimestampNow()) { _type = EntityTypes::Model; _visuallyReady = false; } EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class @Model_ENTITY_COPY_TO@ return properties; } bool ModelEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; @Model_ENTITY_SET_FROM@ withWriteLock([&] { AnimationPropertyGroup animationProperties = _animationProperties; animationProperties.setProperties(properties); bool somethingChangedInAnimations = applyNewAnimationProperties(animationProperties); somethingChanged = somethingChanged || somethingChangedInAnimations; }); return somethingChanged; } EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); @Model_REQUESTED_PROPS@ return requestedProperties; } void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertiesDidntFit, int& propertyCount, OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; @Model_ENTITY_APPEND@ } int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) { int bytesRead = 0; const unsigned char* dataAt = data; bool animationPropertiesChanged = false; @Model_ENTITY_READ@ // grab a local copy of _animationProperties to avoid multiple locks int bytesFromAnimation; AnimationPropertyGroup animationProperties; withReadLock([&] { animationProperties = _animationProperties; bytesFromAnimation = animationProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, animationPropertiesChanged); }); if (animationPropertiesChanged) { withWriteLock([&] { applyNewAnimationProperties(animationProperties); }); somethingChanged = true; } bytesRead += bytesFromAnimation; dataAt += bytesFromAnimation; return bytesRead; } // added update function back for property fix void ModelEntityItem::update(const quint64& now) { assert(_lastAnimated > 0); // increment timestamp before checking "hold" auto interval = now - _lastAnimated; _lastAnimated = now; // grab a local copy of _animationProperties to avoid multiple locks auto animationProperties = getAnimationProperties(); // bail on "hold" if (animationProperties.getHold()) { return; } // increment animation frame _currentFrame += (animationProperties.getFps() * ((float)interval) / (float)USECS_PER_SECOND); if (_currentFrame > animationProperties.getLastFrame() + 1.0f) { if (animationProperties.getLoop()) { _currentFrame = animationProperties.computeLoopedFrame(_currentFrame); } else { _currentFrame = animationProperties.getLastFrame(); } } else if (_currentFrame < animationProperties.getFirstFrame()) { if (animationProperties.getFirstFrame() < 0.0f) { _currentFrame = 0.0f; } else { _currentFrame = animationProperties.getFirstFrame(); } } setAnimationCurrentFrame(_currentFrame); EntityItem::update(now); } void ModelEntityItem::debugDump() const { qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " name:" << _name; qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); qCDebug(entities) << " pointer:" << this; @Model_ENTITY_DEBUG@ } void ModelEntityItem::setShapeType(ShapeType type) { bool changed = false; uint32_t flags = 0; withWriteLock([&] { if (type != _shapeType) { if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) { // dynamic and STATIC_MESH are incompatible // since the shape is being set here we clear the dynamic bit _dynamic = false; flags = Simulation::DIRTY_MOTION_TYPE; } _shapeType = type; flags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; changed = true; } }); if (changed) { markDirtyFlags(flags); locationChanged(); } } ShapeType ModelEntityItem::getShapeType() const { ShapeType type = resultWithReadLock<ShapeType>([&] { return _shapeType; }); if (type == SHAPE_TYPE_STATIC_MESH && _dynamic) { // dynamic is incompatible with STATIC_MESH // shouldn't fall in here but just in case --> fall back to COMPOUND type = SHAPE_TYPE_COMPOUND; } if (type == SHAPE_TYPE_COMPOUND && !hasCompoundShapeURL()) { // no compoundURL set --> fall back to SIMPLE_COMPOUND type = SHAPE_TYPE_SIMPLE_COMPOUND; } return type; } glm::vec3 ModelEntityItem::getScaledDimensions() const { glm::vec3 parentScale = getTransform().getScale(); return _unscaledDimensions * parentScale; } void ModelEntityItem::setScaledDimensions(const glm::vec3& value) { glm::vec3 parentScale = getTransform().getScale(); setUnscaledDimensions(value / parentScale); } const Transform ModelEntityItem::getTransform() const { bool success; return getTransform(success); } const Transform ModelEntityItem::getTransform(bool& success, int depth) const { const Transform parentTransform = getParentTransform(success, depth); Transform localTransform = getLocalTransform(); localTransform.postScale(getModelScale()); Transform worldTransform; Transform::mult(worldTransform, parentTransform, localTransform); return worldTransform; } const Transform ModelEntityItem::getTransformWithOnlyLocalRotation(bool& success, int depth) const { const Transform parentTransform = getParentTransform(success, depth); Transform localTransform = getLocalTransform(); localTransform.postScale(getModelScale()); Transform worldTransform; Transform::mult(worldTransform, parentTransform, localTransform); worldTransform.setRotation(localTransform.getRotation()); return worldTransform; } void ModelEntityItem::setAnimationSettings(const QString& value) { // NOTE: this method only called for old bitstream format AnimationPropertyGroup animationProperties; withReadLock([&] { animationProperties = _animationProperties; }); // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, currentFrame, or running, those values will be parsed out and // will over ride the regular animation settings QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); if (settingsMap.contains("fps")) { float fps = settingsMap["fps"].toFloat(); animationProperties.setFps(fps); } // old settings used frameIndex if (settingsMap.contains("frameIndex")) { float currentFrame = settingsMap["frameIndex"].toFloat(); animationProperties.setCurrentFrame(currentFrame); } if (settingsMap.contains("running")) { bool running = settingsMap["running"].toBool(); if (running != animationProperties.getRunning()) { animationProperties.setRunning(running); } } if (settingsMap.contains("firstFrame")) { float firstFrame = settingsMap["firstFrame"].toFloat(); animationProperties.setFirstFrame(firstFrame); } if (settingsMap.contains("lastFrame")) { float lastFrame = settingsMap["lastFrame"].toFloat(); animationProperties.setLastFrame(lastFrame); } if (settingsMap.contains("loop")) { bool loop = settingsMap["loop"].toBool(); animationProperties.setLoop(loop); } if (settingsMap.contains("hold")) { bool hold = settingsMap["hold"].toBool(); animationProperties.setHold(hold); } if (settingsMap.contains("allowTranslation")) { bool allowTranslation = settingsMap["allowTranslation"].toBool(); animationProperties.setAllowTranslation(allowTranslation); } withWriteLock([&] { applyNewAnimationProperties(animationProperties); }); } QString ModelEntityItem::getModelURL() const { return resultWithReadLock<QString>([&] { return _modelURL; }); } void ModelEntityItem::setModelURL(const QString& value) { withWriteLock([&] { _needsRenderUpdate |= _modelURL != value; _modelURL = value; }); } void ModelEntityItem::resizeJointArrays(int newSize) { if (newSize < 0) { return; } _jointDataLock.withWriteLock([&] { if (newSize > _localJointData.size()) { _localJointData.resize(newSize); } }); } void ModelEntityItem::setAnimationJointsData(const QVector<EntityJointData>& jointsData) { resizeJointArrays(jointsData.size()); _jointDataLock.withWriteLock([&] { for (auto index = 0; index < jointsData.size(); ++index) { const auto& newJointData = jointsData[index]; auto& localJointData = _localJointData[index]; if (newJointData.translationSet) { localJointData.joint.translation = newJointData.translation; localJointData.translationDirty = true; } if (newJointData.rotationSet) { localJointData.joint.rotation = newJointData.rotation; localJointData.rotationDirty = true; } } }); } void ModelEntityItem::setJointRotations(const QVector<glm::quat>& rotations) { resizeJointArrays(rotations.size()); _jointDataLock.withWriteLock([&] { _jointRotationsExplicitlySet = rotations.size() > 0; for (int index = 0; index < rotations.size(); index++) { auto& jointData = _localJointData[index]; if (jointData.joint.rotationSet) { jointData.joint.rotation = rotations[index]; jointData.rotationDirty = true; } } }); } void ModelEntityItem::setJointRotationsSet(const QVector<bool>& rotationsSet) { resizeJointArrays(rotationsSet.size()); _jointDataLock.withWriteLock([&] { _jointRotationsExplicitlySet = rotationsSet.size() > 0; for (int index = 0; index < rotationsSet.size(); index++) { _localJointData[index].joint.rotationSet = rotationsSet[index]; } }); } void ModelEntityItem::setJointTranslations(const QVector<glm::vec3>& translations) { resizeJointArrays(translations.size()); _jointDataLock.withWriteLock([&] { _jointTranslationsExplicitlySet = translations.size() > 0; for (int index = 0; index < translations.size(); index++) { auto& jointData = _localJointData[index]; if (jointData.joint.translationSet) { jointData.joint.translation = translations[index]; jointData.translationDirty = true; } } }); } void ModelEntityItem::setJointTranslationsSet(const QVector<bool>& translationsSet) { resizeJointArrays(translationsSet.size()); _jointDataLock.withWriteLock([&] { _jointTranslationsExplicitlySet = translationsSet.size() > 0; for (int index = 0; index < translationsSet.size(); index++) { _localJointData[index].joint.translationSet = translationsSet[index]; } }); } QVector<glm::quat> ModelEntityItem::getJointRotations() const { QVector<glm::quat> result; _jointDataLock.withReadLock([&] { if (_jointRotationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.rotation; } } }); return result; } QVector<bool> ModelEntityItem::getJointRotationsSet() const { QVector<bool> result; _jointDataLock.withReadLock([&] { if (_jointRotationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.rotationSet; } } }); return result; } QVector<glm::vec3> ModelEntityItem::getJointTranslations() const { QVector<glm::vec3> result; _jointDataLock.withReadLock([&] { if (_jointTranslationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.translation; } } }); return result; } QVector<bool> ModelEntityItem::getJointTranslationsSet() const { QVector<bool> result; _jointDataLock.withReadLock([&] { if (_jointTranslationsExplicitlySet) { result.resize(_localJointData.size()); for (auto i = 0; i < _localJointData.size(); ++i) { result[i] = _localJointData[i].joint.translationSet; } } }); return result; } bool ModelEntityItem::hasModel() const { return resultWithReadLock<bool>([&] { return !_modelURL.isEmpty(); }); } bool ModelEntityItem::hasCompoundShapeURL() const { return resultWithReadLock<bool>([&] { return !_compoundShapeURL.isEmpty(); }); } QString ModelEntityItem::getCompoundShapeURL() const { return resultWithReadLock<QString>([&] { return _compoundShapeURL; }); } void ModelEntityItem::setCompoundShapeURL(const QString& url) { withWriteLock([&] { _compoundShapeURL = url; }); } // Animation related items... AnimationPropertyGroup ModelEntityItem::getAnimationProperties() const { return resultWithReadLock<AnimationPropertyGroup>([&] { return _animationProperties; }); } bool ModelEntityItem::hasAnimation() const { return resultWithReadLock<bool>([&] { return !_animationProperties.getUrl().isEmpty(); }); } QString ModelEntityItem::getAnimationURL() const { return resultWithReadLock<QString>([&] { return _animationProperties.getUrl(); }); } void ModelEntityItem::setAnimationCurrentFrame(float value) { withWriteLock([&] { _animationProperties.setCurrentFrame(value); }); } bool ModelEntityItem::getAnimationAllowTranslation() const { return resultWithReadLock<bool>([&] { return _animationProperties.getAllowTranslation();