From 83f60d6e97b5f9a01f3610d917267250b3f772b7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 23 Dec 2015 15:43:50 -0800 Subject: [PATCH] make entity properties for model-entity joint-states --- .../src/RenderableModelEntityItem.cpp | 151 +++++++++++++---- .../src/RenderableModelEntityItem.h | 25 ++- .../entities/src/EntityItemProperties.cpp | 26 +++ libraries/entities/src/EntityItemProperties.h | 5 + .../entities/src/EntityItemPropertiesMacros.h | 14 ++ libraries/entities/src/EntityPropertyFlags.h | 6 + libraries/entities/src/ModelEntityItem.cpp | 155 +++++++++++------- libraries/entities/src/ModelEntityItem.h | 29 +++- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/octree/src/OctreePacketData.cpp | 46 +++++- libraries/octree/src/OctreePacketData.h | 18 +- libraries/shared/src/RegisteredMetaTypes.cpp | 98 +++++++++-- libraries/shared/src/RegisteredMetaTypes.h | 8 + 14 files changed, 449 insertions(+), 135 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 61ad4d2c2a..c77a274692 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -230,8 +231,8 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p return true; } - -void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, + +void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) { pendingChanges.removeItem(_myMetaItem); if (_model) { @@ -239,6 +240,80 @@ void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::sha } } +void RenderableModelEntityItem::resizeJointArrays(int newSize) { + if (newSize < 0) { + if (_model && _model->isActive() && _model->isLoaded() && !_needsInitialSimulation) { + newSize = _model->getJointStateCount(); + } + } + ModelEntityItem::resizeJointArrays(newSize); +} + +bool RenderableModelEntityItem::getAnimationFrame() { + bool newFrame = false; + + if (!_model || !_model->isActive() || !_model->isLoaded() || _needsInitialSimulation) { + return false; + } + + if (!hasAnimation() || !_jointMappingCompleted) { + return false; + } + AnimationPointer myAnimation = getAnimation(_animationProperties.getURL()); // FIXME: this could be optimized + if (myAnimation && myAnimation->isLoaded()) { + + const QVector& frames = myAnimation->getFramesReference(); // NOTE: getFrames() is too heavy + auto& fbxJoints = myAnimation->getGeometry().joints; + + int frameCount = frames.size(); + if (frameCount > 0) { + int animationCurrentFrame = (int)(glm::floor(getAnimationCurrentFrame())) % frameCount; + if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) { + animationCurrentFrame = 0; + } + + if (animationCurrentFrame != _lastKnownCurrentFrame) { + _lastKnownCurrentFrame = animationCurrentFrame; + newFrame = true; + + resizeJointArrays(); + if (_jointMapping.size() != _model->getJointStateCount()) { + qDebug() << "BLERG" << _jointMapping.size() << _model->getJointStateCount(); + assert(false); + } + for (int j = 0; j < _jointMapping.size(); j++) { + int index = _jointMapping[j]; + if (index >= 0) { + if (index >= frames[animationCurrentFrame].rotations.size() || + index >= frames[animationCurrentFrame].translations.size()) { + return false; + } + const glm::quat rotation = frames[animationCurrentFrame].rotations[index]; + const glm::vec3 translation = frames[animationCurrentFrame].translations[index]; + + glm::mat4 translationMat = glm::translate(translation); + glm::mat4 rotationMat = glm::mat4_cast(rotation); + glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform * + rotationMat * fbxJoints[index].postTransform); + _absoluteJointTranslationsInObjectFrame[j] = extractTranslation(finalMat); + _absoluteJointTranslationsInObjectFrameSet[j] = true; + _absoluteJointTranslationsInObjectFrameDirty[j] = true; + + // XXX Tony will fix this better in some other PR + // _absoluteJointRotationsInObjectFrame[j] = glmExtractRotation(finalMat); + _absoluteJointRotationsInObjectFrame[j] = fbxJoints[index].preRotation * rotation; + // XXX + + _absoluteJointRotationsInObjectFrameSet[j] = true; + _absoluteJointRotationsInObjectFrameDirty[j] = true; + } + } + } + } + } + + return newFrame; +} // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles // the per frame simulation/update that might be required if the models properties changed. @@ -292,40 +367,32 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } if (_model) { - // handle script updates... - _scriptSetFrameDataLock.withWriteLock([&] { - while (!_scriptSetFrameDataRotationsIndexes.empty()) { - int index = _scriptSetFrameDataRotationsIndexes.dequeue(); - glm::quat rotation = _scriptSetFrameDataRotations.dequeue(); - _model->setJointRotation(index, true, rotation, 1.0f); - } - while (!_scriptSetFrameDataTranslationsIndexes.empty()) { - int index = _scriptSetFrameDataTranslationsIndexes.dequeue(); - glm::vec3 translation = _scriptSetFrameDataTranslations.dequeue(); - _model->setJointTranslation(index, true, translation, 1.0f); - } - }); - - // handle animations... if (hasAnimation()) { if (!jointsMapped()) { QStringList modelJointNames = _model->getJointNames(); mapJoints(modelJointNames); } + } - if (jointsMapped()) { - bool newFrame; - QVector frameDataRotations; - QVector frameDataTranslations; - getAnimationFrame(newFrame, frameDataRotations, frameDataTranslations); - assert(frameDataRotations.size() == frameDataTranslations.size()); - if (newFrame) { - for (int i = 0; i < frameDataRotations.size(); i++) { - _model->setJointState(i, true, frameDataRotations[i], frameDataTranslations[i], 1.0f); - } + _jointDataLock.withWriteLock([&] { + getAnimationFrame(); + + // relay any inbound joint changes from scripts/animation/network to the model/rig + for (int index = 0; index < _absoluteJointRotationsInObjectFrame.size(); index++) { + if (_absoluteJointRotationsInObjectFrameDirty[index]) { + glm::quat rotation = _absoluteJointRotationsInObjectFrame[index]; + _model->setJointRotation(index, true, rotation, 1.0f); + _absoluteJointRotationsInObjectFrameDirty[index] = false; } } - } + for (int index = 0; index < _absoluteJointTranslationsInObjectFrame.size(); index++) { + if (_absoluteJointTranslationsInObjectFrameDirty[index]) { + glm::vec3 translation = _absoluteJointTranslationsInObjectFrame[index]; + _model->setJointTranslation(index, true, translation, 1.0f); + _absoluteJointTranslationsInObjectFrameDirty[index] = false; + } + } + }); bool movingOrAnimating = isMoving() || isAnimatingSomething(); if ((movingOrAnimating || @@ -639,19 +706,31 @@ glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(in } bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, glm::quat& rotation) { - _scriptSetFrameDataLock.withWriteLock([&] { - _scriptSetFrameDataRotationsIndexes.enqueue(index); - _scriptSetFrameDataRotations.enqueue(rotation); + bool result = false; + _jointDataLock.withWriteLock([&] { + resizeJointArrays(); + if (index >= 0 && index < _absoluteJointRotationsInObjectFrame.size()) { + _absoluteJointRotationsInObjectFrame[index] = rotation; + _absoluteJointRotationsInObjectFrameSet[index] = true; + _absoluteJointRotationsInObjectFrameDirty[index] = true; + result = true; + } }); - return true; + return result; } bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int index, glm::vec3& translation) { - _scriptSetFrameDataLock.withWriteLock([&] { - _scriptSetFrameDataTranslationsIndexes.enqueue(index); - _scriptSetFrameDataTranslations.enqueue(translation); + bool result = false; + _jointDataLock.withWriteLock([&] { + resizeJointArrays(); + if (index >= 0 && index < _absoluteJointTranslationsInObjectFrame.size()) { + _absoluteJointTranslationsInObjectFrame[index] = translation; + _absoluteJointTranslationsInObjectFrameSet[index] = true; + _absoluteJointTranslationsInObjectFrameDirty[index] = true; + result = true; + } }); - return true; + return result; } void RenderableModelEntityItem::locationChanged() { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index d0847b66cb..afb26d632d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -33,15 +33,15 @@ public: virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; - virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) override; - + virtual void somethingChangedNotification() override { // FIX ME: this is overly aggressive. We only really need to simulate() if something about // the world space transform has changed and/or if some animation is occurring. - _needsInitialSimulation = true; + _needsInitialSimulation = true; } virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr); @@ -52,12 +52,12 @@ public: virtual void render(RenderArgs* args) override; virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const override; Model* getModel(EntityTreeRenderer* renderer); - + virtual bool needsToCallUpdate() const override; virtual void update(const quint64& now) override; @@ -65,7 +65,7 @@ public: virtual bool isReadyToComputeShape() override; virtual void computeShapeInfo(ShapeInfo& info) override; - + virtual bool contains(const glm::vec3& point) const override; // these are in the frame of this object (model space) @@ -77,9 +77,11 @@ public: virtual void loader() override; virtual void locationChanged() override; + virtual void resizeJointArrays(int newSize = -1) override; + private: void remapTextures(); - + Model* _model = nullptr; bool _needsInitialSimulation = true; bool _needsModelReload = true; @@ -89,17 +91,12 @@ private: bool _originalTexturesRead = false; QVector> _points; bool _dimensionsInitialized = true; - + render::ItemID _myMetaItem; bool _showCollisionHull = false; - // these are used to let scripts set ModelEntityItem joint data - ReadWriteLockable _scriptSetFrameDataLock; - QQueue _scriptSetFrameDataRotations; - QQueue _scriptSetFrameDataRotationsIndexes; - QQueue _scriptSetFrameDataTranslations; - QQueue _scriptSetFrameDataTranslationsIndexes; + bool getAnimationFrame(); }; #endif // hifi_RenderableModelEntityItem_h diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 3a2fdf55d4..ef373bc206 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -262,6 +262,10 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID); CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex); + CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); + CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS, jointRotations); + CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); + CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS, jointTranslations); changedProperties += _animation.getChangedProperties(); changedProperties += _keyLight.getChangedProperties(); @@ -363,6 +367,10 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool if (_type == EntityTypes::Model) { COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL); _animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS, jointTranslations); } if (_type == EntityTypes::Model || _type == EntityTypes::Zone || _type == EntityTypes::ParticleEffect) { @@ -739,6 +747,14 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID); ADD_PROPERTY_TO_MAP(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID); + ADD_PROPERTY_TO_MAP(PROP_PARENT_ID, ParentID, parentID, QUuid); + ADD_PROPERTY_TO_MAP(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, uint16_t); + + ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector); + ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector); + ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector); + ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector); + ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_URL, Animation, animation, URL, url); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FPS, Animation, animation, FPS, fps); ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame); @@ -943,6 +959,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem _staticAnimation.setProperties(properties); _staticAnimation.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); + + APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, properties.getJointRotationsSet()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, properties.getJointRotations()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, properties.getJointTranslationsSet()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, properties.getJointTranslations()); } if (properties.getType() == EntityTypes::Light) { @@ -1228,6 +1249,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); properties.getAnimation().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); + + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS, QVector, setJointRotations); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); } if (properties.getType() == EntityTypes::Light) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 5420e75aed..f8bdfcc0dd 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -198,6 +198,11 @@ public: DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION); + DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector, QVector()); + DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector, QVector()); + DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector, QVector()); + DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector, QVector()); + static QString getBackgroundModeString(BackgroundMode mode); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 304e6f672c..a8aa23a5c9 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -113,6 +113,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { retu inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; } inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorQuatToScriptValue(e, v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { @@ -173,6 +175,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) typedef glm::vec3 glmVec3; typedef glm::quat glmQuat; typedef QVector qVectorVec3; +typedef QVector qVectorQuat; +typedef QVector qVectorBool; typedef QVector qVectorFloat; inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); } inline quint64 quint64_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); } @@ -235,6 +239,16 @@ inline qVectorVec3 qVectorVec3_convertFromScriptValue(const QScriptValue& v, boo return qVectorVec3FromScriptValue(v); } +inline qVectorQuat qVectorQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = true; + return qVectorQuatFromScriptValue(v); +} + +inline qVectorBool qVectorBool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = true; + return qVectorBoolFromScriptValue(v); +} + inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = false; /// assume it can't be converted QScriptValue x = v.property("x"); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 2ba86a491e..5e38e8bd7c 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -157,6 +157,12 @@ enum EntityPropertyList { PROP_LOCAL_POSITION, // only used to convert values to and from scripts PROP_LOCAL_ROTATION, // only used to convert values to and from scripts + // ModelEntity joint state + PROP_JOINT_ROTATIONS_SET, + PROP_JOINT_ROTATIONS, + PROP_JOINT_TRANSLATIONS_SET, + PROP_JOINT_TRANSLATIONS, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index a1f16ee251..4f8ba1cc6c 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -133,6 +133,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, somethingChanged = true; } + READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); + READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector, setJointRotations); + READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); + READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); + return bytesRead; } @@ -145,6 +150,10 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& requestedProperties += PROP_TEXTURES; requestedProperties += PROP_SHAPE_TYPE; requestedProperties += _animationProperties.getEntityProperties(params); + requestedProperties += PROP_JOINT_ROTATIONS_SET; + requestedProperties += PROP_JOINT_ROTATIONS; + requestedProperties += PROP_JOINT_TRANSLATIONS_SET; + requestedProperties += PROP_JOINT_TRANSLATIONS; return requestedProperties; } @@ -168,6 +177,11 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit propertyFlags, propertiesDidntFit, propertyCount, appendState); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); + + APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, getJointRotationsSet()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, getJointRotations()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet()); + APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, getJointTranslations()); } @@ -214,62 +228,6 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) { } } -void ModelEntityItem::getAnimationFrame(bool& newFrame, - QVector& rotationsResult, QVector& translationsResult) { - newFrame = false; - - if (!hasAnimation() || !_jointMappingCompleted) { - rotationsResult = _lastKnownFrameDataRotations; - translationsResult = _lastKnownFrameDataTranslations; - } - AnimationPointer myAnimation = getAnimation(_animationProperties.getURL()); // FIXME: this could be optimized - if (myAnimation && myAnimation->isLoaded()) { - - const QVector& frames = myAnimation->getFramesReference(); // NOTE: getFrames() is too heavy - auto& fbxJoints = myAnimation->getGeometry().joints; - - int frameCount = frames.size(); - if (frameCount > 0) { - int animationCurrentFrame = (int)(glm::floor(getAnimationCurrentFrame())) % frameCount; - if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) { - animationCurrentFrame = 0; - } - - if (animationCurrentFrame != _lastKnownCurrentFrame) { - _lastKnownCurrentFrame = animationCurrentFrame; - newFrame = true; - - const QVector& rotations = frames[animationCurrentFrame].rotations; - const QVector& translations = frames[animationCurrentFrame].translations; - - _lastKnownFrameDataRotations.resize(_jointMapping.size()); - _lastKnownFrameDataTranslations.resize(_jointMapping.size()); - - for (int j = 0; j < _jointMapping.size(); j++) { - int index = _jointMapping[j]; - if (index >= 0) { - glm::mat4 translationMat; - if (index < translations.size()) { - translationMat = glm::translate(translations[index]); - } - glm::mat4 rotationMat; - if (index < rotations.size()) { - rotationMat = glm::mat4_cast(rotations[index]); - } - glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform * - rotationMat * fbxJoints[index].postTransform); - _lastKnownFrameDataTranslations[j] = extractTranslation(finalMat); - _lastKnownFrameDataRotations[j] = glmExtractRotation(finalMat); - } - } - } - } - } - - rotationsResult = _lastKnownFrameDataRotations; - translationsResult = _lastKnownFrameDataTranslations; -} - bool ModelEntityItem::isAnimatingSomething() const { return getAnimationIsPlaying() && getAnimationFPS() != 0.0f && @@ -412,3 +370,88 @@ void ModelEntityItem::setAnimationFPS(float value) { bool ModelEntityItem::shouldBePhysical() const { return getShapeType() != SHAPE_TYPE_NONE; } + +void ModelEntityItem::resizeJointArrays(int newSize) { + if (newSize >= 0 && newSize > _absoluteJointRotationsInObjectFrame.size()) { + _absoluteJointRotationsInObjectFrame.resize(newSize); + _absoluteJointRotationsInObjectFrameSet.resize(newSize); + _absoluteJointRotationsInObjectFrameDirty.resize(newSize); + _absoluteJointTranslationsInObjectFrame.resize(newSize); + _absoluteJointTranslationsInObjectFrameSet.resize(newSize); + _absoluteJointTranslationsInObjectFrameDirty.resize(newSize); + } +} + +void ModelEntityItem::setJointRotations(const QVector& rotations) { + _jointDataLock.withWriteLock([&] { + resizeJointArrays(rotations.size()); + for (int index = 0; index < rotations.size(); index++) { + if (_absoluteJointRotationsInObjectFrameSet[index]) { + _absoluteJointRotationsInObjectFrame[index] = rotations[index]; + _absoluteJointRotationsInObjectFrameDirty[index] = true; + } + } + }); +} + +void ModelEntityItem::setJointRotationsSet(const QVector& rotationsSet) { + _jointDataLock.withWriteLock([&] { + resizeJointArrays(rotationsSet.size()); + for (int index = 0; index < rotationsSet.size(); index++) { + _absoluteJointRotationsInObjectFrameSet[index] = rotationsSet[index]; + } + }); +} + +void ModelEntityItem::setJointTranslations(const QVector& translations) { + _jointDataLock.withWriteLock([&] { + resizeJointArrays(translations.size()); + for (int index = 0; index < translations.size(); index++) { + if (_absoluteJointTranslationsInObjectFrameSet[index]) { + _absoluteJointTranslationsInObjectFrame[index] = translations[index]; + _absoluteJointTranslationsInObjectFrameSet[index] = true; + } + } + }); +} + +void ModelEntityItem::setJointTranslationsSet(const QVector& translationsSet) { + _jointDataLock.withWriteLock([&] { + resizeJointArrays(translationsSet.size()); + for (int index = 0; index < translationsSet.size(); index++) { + _absoluteJointTranslationsInObjectFrameSet[index] = translationsSet[index]; + } + }); +} + +QVector ModelEntityItem::getJointRotations() const { + QVector result; + _jointDataLock.withReadLock([&] { + result = _absoluteJointRotationsInObjectFrame; + }); + return result; +} + +QVector ModelEntityItem::getJointRotationsSet() const { + QVector result; + _jointDataLock.withReadLock([&] { + result = _absoluteJointRotationsInObjectFrameSet; + }); + return result; +} + +QVector ModelEntityItem::getJointTranslations() const { + QVector result; + _jointDataLock.withReadLock([&] { + result = _absoluteJointTranslationsInObjectFrame; + }); + return result; +} + +QVector ModelEntityItem::getJointTranslationsSet() const { + QVector result; + _jointDataLock.withReadLock([&] { + result = _absoluteJointTranslationsInObjectFrameSet; + }); + return result; +} diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index b08fed5970..232c5c677a 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -103,7 +103,6 @@ public: float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); } void mapJoints(const QStringList& modelJointNames); - void getAnimationFrame(bool& newFrame, QVector& rotationsResult, QVector& translationsResult); bool jointsMapped() const { return _jointMappingURL == getAnimationURL() && _jointMappingCompleted; } bool getAnimationIsPlaying() const { return _animationLoop.getRunning(); } @@ -121,14 +120,34 @@ public: virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); } virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); } + void setJointRotations(const QVector& rotations); + void setJointRotationsSet(const QVector& rotationsSet); + void setJointTranslations(const QVector& translations); + void setJointTranslationsSet(const QVector& translationsSet); + QVector getJointRotations() const; + QVector getJointRotationsSet() const; + QVector getJointTranslations() const; + QVector getJointTranslationsSet() const; + private: void setAnimationSettings(const QString& value); // only called for old bitstream format protected: - QVector _lastKnownFrameDataRotations; - QVector _lastKnownFrameDataTranslations; + // these are used: + // - to bounce joint data from an animation into the model/rig. + // - to relay changes from scripts to model/rig. + // - to relay between network and model/rig + // they aren't currently updated from data in the model/rig, and they don't have a direct effect + // on what's rendered. + ReadWriteLockable _jointDataLock; + QVector _absoluteJointRotationsInObjectFrame; + QVector _absoluteJointRotationsInObjectFrameSet; // ever set? + QVector _absoluteJointRotationsInObjectFrameDirty; // needs a relay to model/rig? + QVector _absoluteJointTranslationsInObjectFrame; + QVector _absoluteJointTranslationsInObjectFrameSet; // ever set? + QVector _absoluteJointTranslationsInObjectFrameDirty; // needs a relay to model/rig? int _lastKnownCurrentFrame; - + virtual void resizeJointArrays(int newSize = -1); bool isAnimatingSomething() const; @@ -145,7 +164,7 @@ protected: // used on client side bool _jointMappingCompleted; - QVector _jointMapping; + QVector _jointMapping; // domain is index into model-joints, range is index into animation-joints QString _jointMappingURL; static AnimationPointer getAnimation(const QString& url); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 4daf7f83b6..7a428aa0f2 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP; + return VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE; case PacketType::AvatarData: case PacketType::BulkAvatarData: return 17; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 5daa185af4..869da542e9 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -162,5 +162,6 @@ const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; const PacketVersion VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52; +const PacketVersion VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE = 53; #endif // hifi_PacketHeaders_h diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index f063c60fd7..d515244f64 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -392,6 +392,19 @@ bool OctreePacketData::appendValue(const QVector& value) { return success; } +bool OctreePacketData::appendValue(const QVector& value) { + uint16_t qVecSize = value.size(); + bool success = appendValue(qVecSize); + if (success) { + success = append((const unsigned char*)value.constData(), qVecSize * sizeof(glm::quat)); + if (success) { + _bytesOfValues += qVecSize * sizeof(glm::quat); + _totalBytesOfValues += qVecSize * sizeof(glm::quat); + } + } + return success; +} + bool OctreePacketData::appendValue(const QVector& value) { uint16_t qVecSize = value.size(); bool success = appendValue(qVecSize); @@ -405,6 +418,19 @@ bool OctreePacketData::appendValue(const QVector& value) { return success; } +bool OctreePacketData::appendValue(const QVector& value) { + uint16_t qVecSize = value.size(); + bool success = appendValue(qVecSize); + if (success) { + success = append((const unsigned char*)value.constData(), qVecSize * sizeof(bool)); + if (success) { + _bytesOfValues += qVecSize * sizeof(bool); + _totalBytesOfValues += qVecSize * sizeof(bool); + } + } + return success; +} + bool OctreePacketData::appendValue(const glm::quat& value) { const size_t VALUES_PER_QUAT = 4; const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT; @@ -621,6 +647,15 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVecto return sizeof(uint16_t) + length * sizeof(glm::vec3); } +int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVector& result) { + uint16_t length; + memcpy(&length, dataBytes, sizeof(uint16_t)); + dataBytes += sizeof(length); + result.resize(length); + memcpy(result.data(), dataBytes, length * sizeof(glm::quat)); + return sizeof(uint16_t) + length * sizeof(glm::quat); +} + int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVector& result) { uint16_t length; memcpy(&length, dataBytes, sizeof(uint16_t)); @@ -630,7 +665,16 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto return sizeof(uint16_t) + length * sizeof(float); } -int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) { +int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVector& result) { + uint16_t length; + memcpy(&length, dataBytes, sizeof(uint16_t)); + dataBytes += sizeof(length); + result.resize(length); + memcpy(result.data(), dataBytes, length * sizeof(bool)); + return sizeof(uint16_t) + length * sizeof(bool); +} + +int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) { uint16_t length; memcpy(&length, dataBytes, sizeof(length)); dataBytes += sizeof(length); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 2c86d518ad..d87a456be5 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -165,19 +165,25 @@ public: /// appends a non-position vector to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const glm::vec3& value); - - //appends a QVector of vec3's to the end of the stream, may fail if new data stream is too long to fit in packet + + /// appends a QVector of vec3s to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const QVector& value); - - //appends a QVector of floats to the end of the stream, may fail if new data stream is too long to fit in packet + + /// appends a QVector of quats to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const QVector& value); + + /// appends a QVector of floats to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const QVector& value); + /// appends a QVector of bools to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const QVector& value); + /// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const glm::quat& value); /// appends a bool value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(bool value); - + /// appends a string value to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const QString& string); @@ -251,7 +257,9 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result); static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); + static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); + static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); private: diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 008ac238d5..d37cf4c73f 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -20,6 +20,8 @@ static int vec4MetaTypeId = qRegisterMetaType(); static int vec3MetaTypeId = qRegisterMetaType(); static int qVectorVec3MetaTypeId = qRegisterMetaType>(); +static int qVectorQuatMetaTypeId = qRegisterMetaType>(); +static int qVectorBoolMetaTypeId = qRegisterMetaType>(); static int vec2MetaTypeId = qRegisterMetaType(); static int quatMetaTypeId = qRegisterMetaType(); static int xColorMetaTypeId = qRegisterMetaType(); @@ -31,6 +33,8 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue); + qScriptRegisterMetaType(engine, qVectorQuatToScriptValue, qVectorQuatFromScriptValue); + qScriptRegisterMetaType(engine, qVectorBoolToScriptValue, qVectorBoolFromScriptValue); qScriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue); qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); @@ -87,6 +91,42 @@ QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVectornewObject(); + if (quat.x != quat.x || quat.y != quat.y || quat.z != quat.z || quat.w != quat.w) { + // if quat contains a NaN don't try to convert it + return obj; + } + obj.setProperty("x", quat.x); + obj.setProperty("y", quat.y); + obj.setProperty("z", quat.z); + obj.setProperty("w", quat.w); + return obj; +} + +void quatFromScriptValue(const QScriptValue &object, glm::quat &quat) { + quat.x = object.property("x").toVariant().toFloat(); + quat.y = object.property("y").toVariant().toFloat(); + quat.z = object.property("z").toVariant().toFloat(); + quat.w = object.property("w").toVariant().toFloat(); +} + +QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector& vector) { + QScriptValue array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array.setProperty(i, quatToScriptValue(engine, vector.at(i))); + } + return array; +} + +QScriptValue qVectorBoolToScriptValue(QScriptEngine* engine, const QVector& vector) { + QScriptValue array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array.setProperty(i, vector.at(i)); + } + return array; +} + QVector qVectorFloatFromScriptValue(const QScriptValue& array) { if(!array.isArray()) { return QVector(); @@ -149,7 +189,7 @@ QVector qVectorVec3FromScriptValue(const QScriptValue& array){ void qVectorVec3FromScriptValue(const QScriptValue& array, QVector& vector ) { int length = array.property("length").toInteger(); - + for (int i = 0; i < length; i++) { glm::vec3 newVec3 = glm::vec3(); vec3FromScriptValue(array.property(i), newVec3); @@ -157,6 +197,46 @@ void qVectorVec3FromScriptValue(const QScriptValue& array, QVector& v } } +QVector qVectorQuatFromScriptValue(const QScriptValue& array){ + QVector newVector; + int length = array.property("length").toInteger(); + + for (int i = 0; i < length; i++) { + glm::quat newQuat = glm::quat(); + quatFromScriptValue(array.property(i), newQuat); + newVector << newQuat; + } + return newVector; +} + +void qVectorQuatFromScriptValue(const QScriptValue& array, QVector& vector ) { + int length = array.property("length").toInteger(); + + for (int i = 0; i < length; i++) { + glm::quat newQuat = glm::quat(); + quatFromScriptValue(array.property(i), newQuat); + vector << newQuat; + } +} + +QVector qVectorBoolFromScriptValue(const QScriptValue& array){ + QVector newVector; + int length = array.property("length").toInteger(); + + for (int i = 0; i < length; i++) { + newVector << array.property(i).toBool(); + } + return newVector; +} + +void qVectorBoolFromScriptValue(const QScriptValue& array, QVector& vector ) { + int length = array.property("length").toInteger(); + + for (int i = 0; i < length; i++) { + vector << array.property(i).toBool(); + } +} + QScriptValue vec2toScriptValue(QScriptEngine* engine, const glm::vec2 &vec2) { QScriptValue obj = engine->newObject(); obj.setProperty("x", vec2.x); @@ -169,22 +249,6 @@ void vec2FromScriptValue(const QScriptValue &object, glm::vec2 &vec2) { vec2.y = object.property("y").toVariant().toFloat(); } -QScriptValue quatToScriptValue(QScriptEngine* engine, const glm::quat& quat) { - QScriptValue obj = engine->newObject(); - obj.setProperty("x", quat.x); - obj.setProperty("y", quat.y); - obj.setProperty("z", quat.z); - obj.setProperty("w", quat.w); - return obj; -} - -void quatFromScriptValue(const QScriptValue &object, glm::quat& quat) { - quat.x = object.property("x").toVariant().toFloat(); - quat.y = object.property("y").toVariant().toFloat(); - quat.z = object.property("z").toVariant().toFloat(); - quat.w = object.property("w").toVariant().toFloat(); -} - QScriptValue qRectToScriptValue(QScriptEngine* engine, const QRect& rect) { QScriptValue obj = engine->newObject(); obj.setProperty("x", rect.x()); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index cd1e3b0d3e..a2941803ca 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -61,6 +61,14 @@ QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector); QVector qVectorVec3FromScriptValue(const QScriptValue& array); +QScriptValue qVectorQuatToScriptValue(QScriptEngine* engine, const QVector& vector); +void qVectorQuatFromScriptValue(const QScriptValue& array, QVector& vector); +QVector qVectorQuatFromScriptValue(const QScriptValue& array); + +QScriptValue qVectorBoolToScriptValue(QScriptEngine* engine, const QVector& vector); +void qVectorBoolFromScriptValue(const QScriptValue& array, QVector& vector); +QVector qVectorBoolFromScriptValue(const QScriptValue& array); + QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector); void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vector); QVector qVectorFloatFromScriptValue(const QScriptValue& array);