630 lines · 21.7 KB · Text
RawDownload
////  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.