diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index af261f490b..ecc51132b9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2337,6 +2337,7 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); initAnimGraph(); + initFlow(); _skeletonModelLoaded = true; } QObject::disconnect(*skeletonConnection); @@ -5383,6 +5384,37 @@ void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& phys } } +void MyAvatar::initFlow() { + auto &flowData = _skeletonModel->getHFMModel().flowData; + if (flowData._physicsData.size() > 0) { + QVariantMap physicsConfig; + QVariantMap collisionsConfig; + for (auto &data : flowData._physicsData) { + QJsonObject map = QJsonDocument::fromJson(data).object(); + if (!map.isEmpty() && map.keys().size() == 1) { + QString group = map.keys()[0]; + if (map[group].isObject()) { + physicsConfig.insert(group, map[group].toObject().toVariantMap()); + } + } + } + for (auto &data : flowData._collisionsData) { + QJsonObject map = QJsonDocument::fromJson(data).object(); + if (!map.isEmpty() && map.keys().size() == 1) { + QString jointName = map.keys()[0]; + if (map[jointName].isObject()) { + collisionsConfig.insert(jointName, map[jointName].toObject().toVariantMap()); + } + } + } + if (collisionsConfig.size() > 0) { + useFlow(true, true, physicsConfig, collisionsConfig); + } else { + useFlow(true, false, physicsConfig); + } + } +} + void MyAvatar::sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const { auto treeRenderer = DependencyManager::get(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 2c8dedd430..c80412c949 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1751,6 +1751,7 @@ private: void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void initHeadBones(); void initAnimGraph(); + void initFlow(); // Avatar Preferences QUrl _fullAvatarURLFromPreferences; diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index 9f3de3302c..c2d8b14ba1 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -273,6 +273,13 @@ public: {} }; +class FlowData { +public: + FlowData() {}; + std::vector _physicsData; + std::vector _collisionsData; +}; + /// The runtime model format. class Model { public: @@ -319,6 +326,7 @@ public: QList blendshapeChannelNames; QMap jointRotationOffsets; + FlowData flowData; }; }; @@ -343,6 +351,7 @@ typedef hfm::Mesh HFMMesh; typedef hfm::AnimationFrame HFMAnimationFrame; typedef hfm::Light HFMLight; typedef hfm::Model HFMModel; +typedef hfm::FlowData FlowData; Q_DECLARE_METATYPE(HFMAnimationFrame) Q_DECLARE_METATYPE(QVector) diff --git a/libraries/model-baker/src/model-baker/Baker.cpp b/libraries/model-baker/src/model-baker/Baker.cpp index dfb18eef86..595f2ae0f7 100644 --- a/libraries/model-baker/src/model-baker/Baker.cpp +++ b/libraries/model-baker/src/model-baker/Baker.cpp @@ -20,6 +20,7 @@ #include "CalculateBlendshapeNormalsTask.h" #include "CalculateBlendshapeTangentsTask.h" #include "PrepareJointsTask.h" +#include "ParseFlowDataTask.h" namespace baker { @@ -101,7 +102,7 @@ namespace baker { class BuildModelTask { public: - using Input = VaryingSet5, std::vector, QMap, QHash>; + using Input = VaryingSet6, std::vector, QMap, QHash, FlowData>; using Output = hfm::Model::Pointer; using JobModel = Job::ModelIO; @@ -111,6 +112,7 @@ namespace baker { hfmModelOut->joints = QVector::fromStdVector(input.get2()); hfmModelOut->jointRotationOffsets = input.get3(); hfmModelOut->jointIndices = input.get4(); + hfmModelOut->flowData = input.get5(); output = hfmModelOut; } }; @@ -157,12 +159,15 @@ namespace baker { // Parse material mapping const auto materialMapping = model.addJob("ParseMaterialMapping", mapping); + // Parse flow data + const auto flowData = model.addJob("ParseFlowData", mapping); + // Combine the outputs into a new hfm::Model const auto buildBlendshapesInputs = BuildBlendshapesTask::Input(blendshapesPerMeshIn, normalsPerBlendshapePerMesh, tangentsPerBlendshapePerMesh).asVarying(); const auto blendshapesPerMeshOut = model.addJob("BuildBlendshapes", buildBlendshapesInputs); const auto buildMeshesInputs = BuildMeshesTask::Input(meshesIn, graphicsMeshes, normalsPerMesh, tangentsPerMesh, blendshapesPerMeshOut).asVarying(); const auto meshesOut = model.addJob("BuildMeshes", buildMeshesInputs); - const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices).asVarying(); + const auto buildModelInputs = BuildModelTask::Input(hfmModelIn, meshesOut, jointsOut, jointRotationOffsets, jointIndices, flowData).asVarying(); const auto hfmModelOut = model.addJob("BuildModel", buildModelInputs); output = Output(hfmModelOut, materialMapping); diff --git a/libraries/model-baker/src/model-baker/ParseFlowDataTask.cpp b/libraries/model-baker/src/model-baker/ParseFlowDataTask.cpp new file mode 100644 index 0000000000..1a298b3d4b --- /dev/null +++ b/libraries/model-baker/src/model-baker/ParseFlowDataTask.cpp @@ -0,0 +1,26 @@ +// +// Created by Luis Cuenca on 5/3/2019 +// Copyright 2019 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 "ParseFlowDataTask.h" + +void ParseFlowDataTask::run(const baker::BakeContextPointer& context, const Input& mapping, Output& output) { + FlowData flowData; + static const QString FLOW_PHYSICS_FIELD = "flowPhysicsData"; + static const QString FLOW_COLLISIONS_FIELD = "flowCollisionsData"; + for (auto &mappingIter = mapping.begin(); mappingIter != mapping.end(); mappingIter++) { + if (mappingIter.key() == FLOW_PHYSICS_FIELD || mappingIter.key() == FLOW_COLLISIONS_FIELD) { + QByteArray flowDataValue = mappingIter.value().toByteArray(); + if (mappingIter.key() == FLOW_PHYSICS_FIELD) { + flowData._physicsData.push_back(flowDataValue); + } else { + flowData._collisionsData.push_back(flowDataValue); + } + } + } + output = flowData; +} diff --git a/libraries/model-baker/src/model-baker/ParseFlowDataTask.h b/libraries/model-baker/src/model-baker/ParseFlowDataTask.h new file mode 100644 index 0000000000..3c85430165 --- /dev/null +++ b/libraries/model-baker/src/model-baker/ParseFlowDataTask.h @@ -0,0 +1,24 @@ +// +// Created by Luis Cuenca on 3/7/2019 +// Copyright 2019 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_ParseFlowDataTask_h +#define hifi_ParseFlowDataTask_h + +#include +#include "Engine.h" + +class ParseFlowDataTask { +public: + using Input = QVariantHash; + using Output = FlowData; + using JobModel = baker::Job::ModelIO; + + void run(const baker::BakeContextPointer& context, const Input& input, Output& output); +}; + +#endif // hifi_ParseFlowDataTask_h