diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt index 9930a9e152..19dce330c1 100644 --- a/android/app/CMakeLists.txt +++ b/android/app/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME native-lib) setup_hifi_library() -link_hifi_libraries(shared task networking gl gpu qml image fbx render-utils physics entities octree ${PLATFORM_GL_BACKEND}) +link_hifi_libraries(shared task networking gl gpu qml image fbx hfm render-utils physics entities octree ${PLATFORM_GL_BACKEND}) target_opengl() target_bullet() diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index c73e8e1d34..1500d7b98e 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -11,7 +11,7 @@ setup_memory_debugger() # link in the shared libraries link_hifi_libraries( - audio avatars octree gpu graphics fbx entities + audio avatars octree gpu graphics fbx hfm entities networking animation recording shared script-engine embedded-webserver controllers physics plugins midi image ) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 50247b1145..e6d83e7890 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -206,7 +206,7 @@ endif() link_hifi_libraries( shared workload task octree ktx gpu gl procedural graphics graphics-scripting render pointers - recording fbx networking model-networking entities avatars trackers + recording hfm fbx networking model-networking entities avatars trackers audio audio-client animation script-engine physics render-utils entities-renderer avatars-renderer ui qml auto-updater midi controllers plugins image trackers diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 21d3477d7e..a7fc0b9e20 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -235,7 +235,7 @@ bool ModelPackager::zipModel() { return true; } -void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const HFMModel& hfmModel) { +void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const hfm::Model& hfmModel) { bool isBodyType = _modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL; diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index ed86f15008..849f6ac3da 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -19,7 +19,9 @@ #include "ui/ModelsBrowser.h" -class HFMModel; +namespace hfm { + class Model; +}; class ModelPackager : public QObject { public: @@ -32,7 +34,7 @@ private: bool editProperties(); bool zipModel(); - void populateBasicMapping(QVariantHash& mapping, QString filename, const HFMModel& hfmModel); + void populateBasicMapping(QVariantHash& mapping, QString filename, const hfm::Model& hfmModel); void listTextures(); bool copyTextures(const QString& oldDir, const QDir& newDir); @@ -44,7 +46,7 @@ private: QString _scriptDir; QVariantHash _mapping; - std::unique_ptr _hfmModel; + std::unique_ptr _hfmModel; QStringList _textures; QStringList _scripts; }; diff --git a/libraries/animation/CMakeLists.txt b/libraries/animation/CMakeLists.txt index 1ec6194afd..30addadcaa 100644 --- a/libraries/animation/CMakeLists.txt +++ b/libraries/animation/CMakeLists.txt @@ -3,5 +3,6 @@ setup_hifi_library(Network Script) link_hifi_libraries(shared graphics fbx) include_hifi_library_headers(networking) include_hifi_library_headers(gpu) +include_hifi_library_headers(hfm) target_nsight() diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index 89dcc61805..06a3804ece 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -3,6 +3,7 @@ setup_hifi_library(Network Script) link_hifi_libraries(shared shaders gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer) include_hifi_library_headers(avatars) include_hifi_library_headers(networking) +include_hifi_library_headers(hfm) include_hifi_library_headers(fbx) include_hifi_library_headers(recording) include_hifi_library_headers(ktx) diff --git a/libraries/baking/CMakeLists.txt b/libraries/baking/CMakeLists.txt index 9041c3a4f1..cce76f152f 100644 --- a/libraries/baking/CMakeLists.txt +++ b/libraries/baking/CMakeLists.txt @@ -3,5 +3,6 @@ setup_hifi_library(Concurrent) link_hifi_libraries(shared graphics networking ktx image fbx) include_hifi_library_headers(gpu) +include_hifi_library_headers(hfm) target_draco() diff --git a/libraries/baking/src/ModelBaker.h b/libraries/baking/src/ModelBaker.h index cda4478b1d..14a182f622 100644 --- a/libraries/baking/src/ModelBaker.h +++ b/libraries/baking/src/ModelBaker.h @@ -25,6 +25,7 @@ #include #include +#include using TextureBakerThreadGetter = std::function; using GetMaterialIDCallback = std::function ; diff --git a/libraries/display-plugins/CMakeLists.txt b/libraries/display-plugins/CMakeLists.txt index 0674c9fd92..8e966ed9ea 100644 --- a/libraries/display-plugins/CMakeLists.txt +++ b/libraries/display-plugins/CMakeLists.txt @@ -5,6 +5,7 @@ include_hifi_library_headers(gpu) include_hifi_library_headers(model-networking) include_hifi_library_headers(networking) include_hifi_library_headers(graphics) +include_hifi_library_headers(hfm) include_hifi_library_headers(fbx) include_hifi_library_headers(image) include_hifi_library_headers(ktx) diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index cf887bfeff..b08856e8a8 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -8,6 +8,7 @@ include_hifi_library_headers(octree) include_hifi_library_headers(audio) include_hifi_library_headers(physics) include_hifi_library_headers(animation) +include_hifi_library_headers(hfm) include_hifi_library_headers(fbx) include_hifi_library_headers(entities) include_hifi_library_headers(avatars) diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index c547708ffa..c51ae28d5f 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME entities) setup_hifi_library(Network Script) include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") +include_hifi_library_headers(hfm) include_hifi_library_headers(fbx) include_hifi_library_headers(gpu) include_hifi_library_headers(image) diff --git a/libraries/fbx/CMakeLists.txt b/libraries/fbx/CMakeLists.txt index e422af3629..2006d23c60 100644 --- a/libraries/fbx/CMakeLists.txt +++ b/libraries/fbx/CMakeLists.txt @@ -1,7 +1,7 @@ set(TARGET_NAME fbx) setup_hifi_library() -link_hifi_libraries(shared graphics networking image) +link_hifi_libraries(shared graphics networking image hfm) include_hifi_library_headers(gpu image) target_draco() diff --git a/libraries/fbx/src/FBX.h b/libraries/fbx/src/FBX.h index 84caa98ace..90de82e310 100644 --- a/libraries/fbx/src/FBX.h +++ b/libraries/fbx/src/FBX.h @@ -13,20 +13,11 @@ #define hifi_FBX_h_ #include -#include -#include #include #include #include #include -#include - -#include -#include - -#include -#include #if defined(Q_OS_ANDROID) #define FBX_PACK_NORMALS 0 @@ -69,306 +60,4 @@ public: FBXNodeList children; }; - -/// A single blendshape. -class HFMBlendshape { -public: - QVector indices; - QVector vertices; - QVector normals; - QVector tangents; -}; - -struct HFMJointShapeInfo { - // same units and frame as HFMJoint.translation - glm::vec3 avgPoint; - std::vector dots; - std::vector points; - std::vector debugLines; -}; - -/// A single joint (transformation node). -class HFMJoint { -public: - - HFMJointShapeInfo shapeInfo; - QVector freeLineage; - bool isFree; - int parentIndex; - float distanceToParent; - - // http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/SDKRef/a00209.html - - glm::vec3 translation; // T - glm::mat4 preTransform; // Roff * Rp - glm::quat preRotation; // Rpre - glm::quat rotation; // R - glm::quat postRotation; // Rpost - glm::mat4 postTransform; // Rp-1 * Soff * Sp * S * Sp-1 - - // World = ParentWorld * T * (Roff * Rp) * Rpre * R * Rpost * (Rp-1 * Soff * Sp * S * Sp-1) - - glm::mat4 transform; - glm::vec3 rotationMin; // radians - glm::vec3 rotationMax; // radians - glm::quat inverseDefaultRotation; - glm::quat inverseBindRotation; - glm::mat4 bindTransform; - QString name; - bool isSkeletonJoint; - bool bindTransformFoundInCluster; - - // geometric offset is applied in local space but does NOT affect children. - bool hasGeometricOffset; - glm::vec3 geometricTranslation; - glm::quat geometricRotation; - glm::vec3 geometricScaling; -}; - - -/// A single binding to a joint. -class HFMCluster { -public: - - int jointIndex; - glm::mat4 inverseBindMatrix; - Transform inverseBindTransform; -}; - -const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; - -/// A texture map. -class HFMTexture { -public: - QString id; - QString name; - QByteArray filename; - QByteArray content; - - Transform transform; - int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE }; - int texcoordSet; - QString texcoordSetName; - - bool isBumpmap{ false }; - - bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); } -}; - -/// A single part of a mesh (with the same material). -class HFMMeshPart { -public: - - QVector quadIndices; // original indices from the FBX mesh - QVector quadTrianglesIndices; // original indices from the FBX mesh of the quad converted as triangles - QVector triangleIndices; // original indices from the FBX mesh - - QString materialID; -}; - -class HFMMaterial { -public: - HFMMaterial() {}; - HFMMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor, - float shininess, float opacity) : - diffuseColor(diffuseColor), - specularColor(specularColor), - emissiveColor(emissiveColor), - shininess(shininess), - opacity(opacity) {} - - void getTextureNames(QSet& textureList) const; - void setMaxNumPixelsPerTexture(int maxNumPixels); - - glm::vec3 diffuseColor{ 1.0f }; - float diffuseFactor{ 1.0f }; - glm::vec3 specularColor{ 0.02f }; - float specularFactor{ 1.0f }; - - glm::vec3 emissiveColor{ 0.0f }; - float emissiveFactor{ 0.0f }; - - float shininess{ 23.0f }; - float opacity{ 1.0f }; - - float metallic{ 0.0f }; - float roughness{ 1.0f }; - float emissiveIntensity{ 1.0f }; - float ambientFactor{ 1.0f }; - - float bumpMultiplier { 1.0f }; // TODO: to be implemented - - QString materialID; - QString name; - QString shadingModel; - graphics::MaterialPointer _material; - - HFMTexture normalTexture; - HFMTexture albedoTexture; - HFMTexture opacityTexture; - HFMTexture glossTexture; - HFMTexture roughnessTexture; - HFMTexture specularTexture; - HFMTexture metallicTexture; - HFMTexture emissiveTexture; - HFMTexture occlusionTexture; - HFMTexture scatteringTexture; - HFMTexture lightmapTexture; - glm::vec2 lightmapParams{ 0.0f, 1.0f }; - - - bool isPBSMaterial{ false }; - // THe use XXXMap are not really used to drive which map are going or not, debug only - bool useNormalMap{ false }; - bool useAlbedoMap{ false }; - bool useOpacityMap{ false }; - bool useRoughnessMap{ false }; - bool useSpecularMap{ false }; - bool useMetallicMap{ false }; - bool useEmissiveMap{ false }; - bool useOcclusionMap{ false }; - - bool needTangentSpace() const; -}; - -/// A single mesh (with optional blendshapes). -class HFMMesh { -public: - - QVector parts; - - QVector vertices; - QVector normals; - QVector tangents; - QVector colors; - QVector texCoords; - QVector texCoords1; - QVector clusterIndices; - QVector clusterWeights; - QVector originalIndices; - - QVector clusters; - - Extents meshExtents; - glm::mat4 modelTransform; - - QVector blendshapes; - - unsigned int meshIndex; // the order the meshes appeared in the object file - - graphics::MeshPointer _mesh; - bool wasCompressed { false }; - - void createMeshTangents(bool generateFromTexCoords); - void createBlendShapeTangents(bool generateTangents); -}; - -class ExtractedMesh { -public: - HFMMesh mesh; - QMultiHash newIndices; - QVector > blendshapeIndexMaps; - QVector > partMaterialTextures; - QHash texcoordSetMap; -}; - -/**jsdoc - * @typedef {object} FBXAnimationFrame - * @property {Quat[]} rotations - * @property {Vec3[]} translations - */ -/// A single animation frame. -class HFMAnimationFrame { -public: - QVector rotations; - QVector translations; -}; - -/// A light. -class HFMLight { -public: - QString name; - Transform transform; - float intensity; - float fogValue; - glm::vec3 color; - - HFMLight() : - name(), - transform(), - intensity(1.0f), - fogValue(0.0f), - color(1.0f) - {} -}; - -Q_DECLARE_METATYPE(HFMAnimationFrame) -Q_DECLARE_METATYPE(QVector) - -/// The runtime model format. -class HFMModel { -public: - using Pointer = std::shared_ptr; - - QString originalURL; - QString author; - QString applicationName; ///< the name of the application that generated the model - - QVector joints; - QHash jointIndices; ///< 1-based, so as to more easily detect missing indices - bool hasSkeletonJoints; - - QVector meshes; - QVector scripts; - - QHash materials; - - glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file - - int leftEyeJointIndex = -1; - int rightEyeJointIndex = -1; - int neckJointIndex = -1; - int rootJointIndex = -1; - int leanJointIndex = -1; - int headJointIndex = -1; - int leftHandJointIndex = -1; - int rightHandJointIndex = -1; - int leftToeJointIndex = -1; - int rightToeJointIndex = -1; - - float leftEyeSize = 0.0f; // Maximum mesh extents dimension - float rightEyeSize = 0.0f; - - QVector humanIKJointIndices; - - glm::vec3 palmDirection; - - glm::vec3 neckPivot; - - Extents bindExtents; - Extents meshExtents; - - QVector animationFrames; - - int getJointIndex(const QString& name) const { return jointIndices.value(name) - 1; } - QStringList getJointNames() const; - - bool hasBlendedMeshes() const; - - /// Returns the unscaled extents of the model's mesh - Extents getUnscaledMeshExtents() const; - - bool convexHullContains(const glm::vec3& point) const; - - QHash meshIndicesToModelNames; - - /// given a meshIndex this will return the name of the model that mesh belongs to if known - QString getModelNameOfMesh(int meshIndex) const; - - QList blendshapeChannelNames; -}; - -Q_DECLARE_METATYPE(HFMModel) -Q_DECLARE_METATYPE(HFMModel::Pointer) - #endif // hifi_FBX_h_ diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 2cf57e54b4..cea3d079bc 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -33,109 +33,13 @@ #include #include -#include "ModelFormatLogging.h" +#include // TOOL: Uncomment the following line to enable the filtering of all the unkwnon fields of a node so we can break point easily while loading a model with problems... //#define DEBUG_FBXREADER using namespace std; -int HFMModelPointerMetaTypeId = qRegisterMetaType(); - -QStringList HFMModel::getJointNames() const { - QStringList names; - foreach (const HFMJoint& joint, joints) { - names.append(joint.name); - } - return names; -} - -bool HFMModel::hasBlendedMeshes() const { - if (!meshes.isEmpty()) { - foreach (const HFMMesh& mesh, meshes) { - if (!mesh.blendshapes.isEmpty()) { - return true; - } - } - } - return false; -} - -Extents HFMModel::getUnscaledMeshExtents() const { - const Extents& extents = meshExtents; - - // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which - // is captured in the offset matrix - glm::vec3 minimum = glm::vec3(offset * glm::vec4(extents.minimum, 1.0f)); - glm::vec3 maximum = glm::vec3(offset * glm::vec4(extents.maximum, 1.0f)); - Extents scaledExtents = { minimum, maximum }; - - return scaledExtents; -} - -// TODO: Move to graphics::Mesh when Sam's ready -bool HFMModel::convexHullContains(const glm::vec3& point) const { - if (!getUnscaledMeshExtents().containsPoint(point)) { - return false; - } - - auto checkEachPrimitive = [=](HFMMesh& mesh, QVector indices, int primitiveSize) -> bool { - // Check whether the point is "behind" all the primitives. - int verticesSize = mesh.vertices.size(); - for (int j = 0; - j < indices.size() - 2; // -2 in case the vertices aren't the right size -- we access j + 2 below - j += primitiveSize) { - if (indices[j] < verticesSize && - indices[j + 1] < verticesSize && - indices[j + 2] < verticesSize && - !isPointBehindTrianglesPlane(point, - mesh.vertices[indices[j]], - mesh.vertices[indices[j + 1]], - mesh.vertices[indices[j + 2]])) { - // it's not behind at least one so we bail - return false; - } - } - return true; - }; - - // Check that the point is contained in at least one convex mesh. - for (auto mesh : meshes) { - bool insideMesh = true; - - // To be considered inside a convex mesh, - // the point needs to be "behind" all the primitives respective planes. - for (auto part : mesh.parts) { - // run through all the triangles and quads - if (!checkEachPrimitive(mesh, part.triangleIndices, 3) || - !checkEachPrimitive(mesh, part.quadIndices, 4)) { - // If not, the point is outside, bail for this mesh - insideMesh = false; - continue; - } - } - if (insideMesh) { - // It's inside this mesh, return true. - return true; - } - } - - // It wasn't in any mesh, return false. - return false; -} - -QString HFMModel::getModelNameOfMesh(int meshIndex) const { - if (meshIndicesToModelNames.contains(meshIndex)) { - return meshIndicesToModelNames.value(meshIndex); - } - return QString(); -} - -int hfmModelMetaTypeId = qRegisterMetaType(); -int hfmAnimationFrameMetaTypeId = qRegisterMetaType(); -int hfmAnimationFrameVectorMetaTypeId = qRegisterMetaType>(); - - glm::vec3 parseVec3(const QString& string) { QStringList elements = string.split(','); if (elements.isEmpty()) { @@ -362,108 +266,6 @@ HFMBlendshape extractBlendshape(const FBXNode& object) { return blendshape; } -using IndexAccessor = std::function; - -static void setTangents(const HFMMesh& mesh, const IndexAccessor& vertexAccessor, int firstIndex, int secondIndex, - const QVector& vertices, const QVector& normals, QVector& tangents) { - glm::vec3 vertex[2]; - glm::vec3 normal; - glm::vec3* tangent = vertexAccessor(mesh, firstIndex, secondIndex, vertex, normal); - if (tangent) { - glm::vec3 bitangent = glm::cross(normal, vertex[1] - vertex[0]); - if (glm::length(bitangent) < EPSILON) { - return; - } - glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex); - glm::vec3 normalizedNormal = glm::normalize(normal); - *tangent += glm::cross(glm::angleAxis(-atan2f(-texCoordDelta.t, texCoordDelta.s), normalizedNormal) * - glm::normalize(bitangent), normalizedNormal); - } -} - -static void createTangents(const HFMMesh& mesh, bool generateFromTexCoords, - const QVector& vertices, const QVector& normals, QVector& tangents, - IndexAccessor accessor) { - // if we have a normal map (and texture coordinates), we must compute tangents - if (generateFromTexCoords && !mesh.texCoords.isEmpty()) { - tangents.resize(vertices.size()); - - foreach(const HFMMeshPart& part, mesh.parts) { - for (int i = 0; i < part.quadIndices.size(); i += 4) { - setTangents(mesh, accessor, part.quadIndices.at(i), part.quadIndices.at(i + 1), vertices, normals, tangents); - setTangents(mesh, accessor, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2), vertices, normals, tangents); - setTangents(mesh, accessor, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3), vertices, normals, tangents); - setTangents(mesh, accessor, part.quadIndices.at(i + 3), part.quadIndices.at(i), vertices, normals, tangents); - } - // <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0 - // This is most likely evidence of a further problem in extractMesh() - for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) { - setTangents(mesh, accessor, part.triangleIndices.at(i), part.triangleIndices.at(i + 1), vertices, normals, tangents); - setTangents(mesh, accessor, part.triangleIndices.at(i + 1), part.triangleIndices.at(i + 2), vertices, normals, tangents); - setTangents(mesh, accessor, part.triangleIndices.at(i + 2), part.triangleIndices.at(i), vertices, normals, tangents); - } - if ((part.triangleIndices.size() % 3) != 0) { - qCDebug(modelformat) << "Error in extractHFMModel part.triangleIndices.size() is not divisible by three "; - } - } - } -} - -static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape); - -void HFMMesh::createBlendShapeTangents(bool generateTangents) { - for (auto& blendShape : blendshapes) { - _createBlendShapeTangents(*this, generateTangents, blendShape); - } -} - -void HFMMesh::createMeshTangents(bool generateFromTexCoords) { - HFMMesh& mesh = *this; - // This is the only workaround I've found to trick the compiler into understanding that mesh.tangents isn't - // const in the lambda function. - auto& tangents = mesh.tangents; - createTangents(mesh, generateFromTexCoords, mesh.vertices, mesh.normals, mesh.tangents, - [&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) { - outVertices[0] = mesh.vertices[firstIndex]; - outVertices[1] = mesh.vertices[secondIndex]; - outNormal = mesh.normals[firstIndex]; - return &(tangents[firstIndex]); - }); -} - -static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape) { - // Create lookup to get index in blend shape from vertex index in mesh - std::vector reverseIndices; - reverseIndices.resize(mesh.vertices.size()); - std::iota(reverseIndices.begin(), reverseIndices.end(), 0); - - for (int indexInBlendShape = 0; indexInBlendShape < blendShape.indices.size(); ++indexInBlendShape) { - auto indexInMesh = blendShape.indices[indexInBlendShape]; - reverseIndices[indexInMesh] = indexInBlendShape; - } - - createTangents(mesh, generateFromTexCoords, blendShape.vertices, blendShape.normals, blendShape.tangents, - [&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) { - const auto index1 = reverseIndices[firstIndex]; - const auto index2 = reverseIndices[secondIndex]; - - if (index1 < blendShape.vertices.size()) { - outVertices[0] = blendShape.vertices[index1]; - if (index2 < blendShape.vertices.size()) { - outVertices[1] = blendShape.vertices[index2]; - } else { - // Index isn't in the blend shape so return vertex from mesh - outVertices[1] = mesh.vertices[secondIndex]; - } - outNormal = blendShape.normals[index1]; - return &blendShape.tangents[index1]; - } else { - // Index isn't in blend shape so return nullptr - return (glm::vec3*)nullptr; - } - }); -} - QVector getIndices(const QVector ids, QVector modelIDs) { QVector indices; foreach (const QString& id, ids) { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index d9a216eeb8..c74b4dc8ac 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -12,8 +12,6 @@ #ifndef hifi_FBXReader_h #define hifi_FBXReader_h -#include "FBX.h" - #include #include #include @@ -28,6 +26,9 @@ #include #include +#include "FBX.h" +#include + #include #include diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index ff1de30b97..2ec8cfde75 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -25,61 +25,7 @@ #include #include -#include "ModelFormatLogging.h" - -void HFMMaterial::getTextureNames(QSet& textureList) const { - if (!normalTexture.isNull()) { - textureList.insert(normalTexture.name); - } - if (!albedoTexture.isNull()) { - textureList.insert(albedoTexture.name); - } - if (!opacityTexture.isNull()) { - textureList.insert(opacityTexture.name); - } - if (!glossTexture.isNull()) { - textureList.insert(glossTexture.name); - } - if (!roughnessTexture.isNull()) { - textureList.insert(roughnessTexture.name); - } - if (!specularTexture.isNull()) { - textureList.insert(specularTexture.name); - } - if (!metallicTexture.isNull()) { - textureList.insert(metallicTexture.name); - } - if (!emissiveTexture.isNull()) { - textureList.insert(emissiveTexture.name); - } - if (!occlusionTexture.isNull()) { - textureList.insert(occlusionTexture.name); - } - if (!scatteringTexture.isNull()) { - textureList.insert(scatteringTexture.name); - } - if (!lightmapTexture.isNull()) { - textureList.insert(lightmapTexture.name); - } -} - -void HFMMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) { - normalTexture.maxNumPixels = maxNumPixels; - albedoTexture.maxNumPixels = maxNumPixels; - opacityTexture.maxNumPixels = maxNumPixels; - glossTexture.maxNumPixels = maxNumPixels; - roughnessTexture.maxNumPixels = maxNumPixels; - specularTexture.maxNumPixels = maxNumPixels; - metallicTexture.maxNumPixels = maxNumPixels; - emissiveTexture.maxNumPixels = maxNumPixels; - occlusionTexture.maxNumPixels = maxNumPixels; - scatteringTexture.maxNumPixels = maxNumPixels; - lightmapTexture.maxNumPixels = maxNumPixels; -} - -bool HFMMaterial::needTangentSpace() const { - return !normalTexture.isNull(); -} +#include HFMTexture FBXReader::getTexture(const QString& textureID) { HFMTexture texture; diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 5b1c708378..527e3aef75 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -31,7 +31,7 @@ #include #include #include -#include "ModelFormatLogging.h" +#include #include "FBXReader.h" diff --git a/libraries/fbx/src/FBXReader_Node.cpp b/libraries/fbx/src/FBXReader_Node.cpp index 9375dc7b56..cd717998dd 100644 --- a/libraries/fbx/src/FBXReader_Node.cpp +++ b/libraries/fbx/src/FBXReader_Node.cpp @@ -22,7 +22,7 @@ #include #include -#include "ModelFormatLogging.h" +#include template int streamSize() { diff --git a/libraries/fbx/src/GLTFReader.h b/libraries/fbx/src/GLTFReader.h index 44186504f0..cf01aa0c6b 100644 --- a/libraries/fbx/src/GLTFReader.h +++ b/libraries/fbx/src/GLTFReader.h @@ -14,7 +14,7 @@ #include #include -#include "ModelFormatLogging.h" +#include #include "FBXReader.h" diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 87fae0e965..dd8acec9a2 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -28,7 +28,7 @@ #include #include "FBXReader.h" -#include "ModelFormatLogging.h" +#include #include QHash COMMENT_SCALE_HINTS = {{"This file uses centimeters as units", 1.0f / 100.0f}, diff --git a/libraries/fbx/src/OBJWriter.cpp b/libraries/fbx/src/OBJWriter.cpp index 630ac95b9e..b2e191bcbf 100644 --- a/libraries/fbx/src/OBJWriter.cpp +++ b/libraries/fbx/src/OBJWriter.cpp @@ -15,7 +15,7 @@ #include #include #include -#include "ModelFormatLogging.h" +#include static QString formatFloat(double n) { // limit precision to 6, but don't output trailing zeros. diff --git a/libraries/hfm/CMakeLists.txt b/libraries/hfm/CMakeLists.txt new file mode 100644 index 0000000000..553fd935d9 --- /dev/null +++ b/libraries/hfm/CMakeLists.txt @@ -0,0 +1,7 @@ +set(TARGET_NAME hfm) +setup_hifi_library() + +link_hifi_libraries(shared) + +include_hifi_library_headers(gpu) +include_hifi_library_headers(graphics) diff --git a/libraries/hfm/src/hfm/HFM.cpp b/libraries/hfm/src/hfm/HFM.cpp new file mode 100644 index 0000000000..8f01956f17 --- /dev/null +++ b/libraries/hfm/src/hfm/HFM.cpp @@ -0,0 +1,259 @@ +// +// HFM.cpp +// libraries/hfm/src +// +// Created by Sabrina Shanman on 2018/11/06. +// Copyright 2018 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 "HFM.h" + +#include "ModelFormatLogging.h" + +void HFMMaterial::getTextureNames(QSet& textureList) const { + if (!normalTexture.isNull()) { + textureList.insert(normalTexture.name); + } + if (!albedoTexture.isNull()) { + textureList.insert(albedoTexture.name); + } + if (!opacityTexture.isNull()) { + textureList.insert(opacityTexture.name); + } + if (!glossTexture.isNull()) { + textureList.insert(glossTexture.name); + } + if (!roughnessTexture.isNull()) { + textureList.insert(roughnessTexture.name); + } + if (!specularTexture.isNull()) { + textureList.insert(specularTexture.name); + } + if (!metallicTexture.isNull()) { + textureList.insert(metallicTexture.name); + } + if (!emissiveTexture.isNull()) { + textureList.insert(emissiveTexture.name); + } + if (!occlusionTexture.isNull()) { + textureList.insert(occlusionTexture.name); + } + if (!scatteringTexture.isNull()) { + textureList.insert(scatteringTexture.name); + } + if (!lightmapTexture.isNull()) { + textureList.insert(lightmapTexture.name); + } +} + +void HFMMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) { + normalTexture.maxNumPixels = maxNumPixels; + albedoTexture.maxNumPixels = maxNumPixels; + opacityTexture.maxNumPixels = maxNumPixels; + glossTexture.maxNumPixels = maxNumPixels; + roughnessTexture.maxNumPixels = maxNumPixels; + specularTexture.maxNumPixels = maxNumPixels; + metallicTexture.maxNumPixels = maxNumPixels; + emissiveTexture.maxNumPixels = maxNumPixels; + occlusionTexture.maxNumPixels = maxNumPixels; + scatteringTexture.maxNumPixels = maxNumPixels; + lightmapTexture.maxNumPixels = maxNumPixels; +} + +bool HFMMaterial::needTangentSpace() const { + return !normalTexture.isNull(); +} + +static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape); + +void HFMMesh::createBlendShapeTangents(bool generateTangents) { + for (auto& blendShape : blendshapes) { + _createBlendShapeTangents(*this, generateTangents, blendShape); + } +} + +using IndexAccessor = std::function; + +static void setTangents(const HFMMesh& mesh, const IndexAccessor& vertexAccessor, int firstIndex, int secondIndex, + const QVector& vertices, const QVector& normals, QVector& tangents) { + glm::vec3 vertex[2]; + glm::vec3 normal; + glm::vec3* tangent = vertexAccessor(mesh, firstIndex, secondIndex, vertex, normal); + if (tangent) { + glm::vec3 bitangent = glm::cross(normal, vertex[1] - vertex[0]); + if (glm::length(bitangent) < EPSILON) { + return; + } + glm::vec2 texCoordDelta = mesh.texCoords.at(secondIndex) - mesh.texCoords.at(firstIndex); + glm::vec3 normalizedNormal = glm::normalize(normal); + *tangent += glm::cross(glm::angleAxis(-atan2f(-texCoordDelta.t, texCoordDelta.s), normalizedNormal) * + glm::normalize(bitangent), normalizedNormal); + } +} + +static void createTangents(const HFMMesh& mesh, bool generateFromTexCoords, + const QVector& vertices, const QVector& normals, QVector& tangents, + IndexAccessor accessor) { + // if we have a normal map (and texture coordinates), we must compute tangents + if (generateFromTexCoords && !mesh.texCoords.isEmpty()) { + tangents.resize(vertices.size()); + + foreach(const HFMMeshPart& part, mesh.parts) { + for (int i = 0; i < part.quadIndices.size(); i += 4) { + setTangents(mesh, accessor, part.quadIndices.at(i), part.quadIndices.at(i + 1), vertices, normals, tangents); + setTangents(mesh, accessor, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2), vertices, normals, tangents); + setTangents(mesh, accessor, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3), vertices, normals, tangents); + setTangents(mesh, accessor, part.quadIndices.at(i + 3), part.quadIndices.at(i), vertices, normals, tangents); + } + // <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0 + // This is most likely evidence of a further problem in extractMesh() + for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) { + setTangents(mesh, accessor, part.triangleIndices.at(i), part.triangleIndices.at(i + 1), vertices, normals, tangents); + setTangents(mesh, accessor, part.triangleIndices.at(i + 1), part.triangleIndices.at(i + 2), vertices, normals, tangents); + setTangents(mesh, accessor, part.triangleIndices.at(i + 2), part.triangleIndices.at(i), vertices, normals, tangents); + } + if ((part.triangleIndices.size() % 3) != 0) { + qCDebug(modelformat) << "Error in extractHFMModel part.triangleIndices.size() is not divisible by three "; + } + } + } +} + +void HFMMesh::createMeshTangents(bool generateFromTexCoords) { + HFMMesh& mesh = *this; + // This is the only workaround I've found to trick the compiler into understanding that mesh.tangents isn't + // const in the lambda function. + auto& tangents = mesh.tangents; + createTangents(mesh, generateFromTexCoords, mesh.vertices, mesh.normals, mesh.tangents, + [&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) { + outVertices[0] = mesh.vertices[firstIndex]; + outVertices[1] = mesh.vertices[secondIndex]; + outNormal = mesh.normals[firstIndex]; + return &(tangents[firstIndex]); + }); +} + +static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape) { + // Create lookup to get index in blend shape from vertex index in mesh + std::vector reverseIndices; + reverseIndices.resize(mesh.vertices.size()); + std::iota(reverseIndices.begin(), reverseIndices.end(), 0); + + for (int indexInBlendShape = 0; indexInBlendShape < blendShape.indices.size(); ++indexInBlendShape) { + auto indexInMesh = blendShape.indices[indexInBlendShape]; + reverseIndices[indexInMesh] = indexInBlendShape; + } + + createTangents(mesh, generateFromTexCoords, blendShape.vertices, blendShape.normals, blendShape.tangents, + [&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) { + const auto index1 = reverseIndices[firstIndex]; + const auto index2 = reverseIndices[secondIndex]; + + if (index1 < blendShape.vertices.size()) { + outVertices[0] = blendShape.vertices[index1]; + if (index2 < blendShape.vertices.size()) { + outVertices[1] = blendShape.vertices[index2]; + } else { + // Index isn't in the blend shape so return vertex from mesh + outVertices[1] = mesh.vertices[secondIndex]; + } + outNormal = blendShape.normals[index1]; + return &blendShape.tangents[index1]; + } else { + // Index isn't in blend shape so return nullptr + return (glm::vec3*)nullptr; + } + }); +} + +QStringList HFMModel::getJointNames() const { + QStringList names; + foreach (const HFMJoint& joint, joints) { + names.append(joint.name); + } + return names; +} + +bool HFMModel::hasBlendedMeshes() const { + if (!meshes.isEmpty()) { + foreach (const HFMMesh& mesh, meshes) { + if (!mesh.blendshapes.isEmpty()) { + return true; + } + } + } + return false; +} + +Extents HFMModel::getUnscaledMeshExtents() const { + const Extents& extents = meshExtents; + + // even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which + // is captured in the offset matrix + glm::vec3 minimum = glm::vec3(offset * glm::vec4(extents.minimum, 1.0f)); + glm::vec3 maximum = glm::vec3(offset * glm::vec4(extents.maximum, 1.0f)); + Extents scaledExtents = { minimum, maximum }; + + return scaledExtents; +} + +// TODO: Move to graphics::Mesh when Sam's ready +bool HFMModel::convexHullContains(const glm::vec3& point) const { + if (!getUnscaledMeshExtents().containsPoint(point)) { + return false; + } + + auto checkEachPrimitive = [=](HFMMesh& mesh, QVector indices, int primitiveSize) -> bool { + // Check whether the point is "behind" all the primitives. + int verticesSize = mesh.vertices.size(); + for (int j = 0; + j < indices.size() - 2; // -2 in case the vertices aren't the right size -- we access j + 2 below + j += primitiveSize) { + if (indices[j] < verticesSize && + indices[j + 1] < verticesSize && + indices[j + 2] < verticesSize && + !isPointBehindTrianglesPlane(point, + mesh.vertices[indices[j]], + mesh.vertices[indices[j + 1]], + mesh.vertices[indices[j + 2]])) { + // it's not behind at least one so we bail + return false; + } + } + return true; + }; + + // Check that the point is contained in at least one convex mesh. + for (auto mesh : meshes) { + bool insideMesh = true; + + // To be considered inside a convex mesh, + // the point needs to be "behind" all the primitives respective planes. + for (auto part : mesh.parts) { + // run through all the triangles and quads + if (!checkEachPrimitive(mesh, part.triangleIndices, 3) || + !checkEachPrimitive(mesh, part.quadIndices, 4)) { + // If not, the point is outside, bail for this mesh + insideMesh = false; + continue; + } + } + if (insideMesh) { + // It's inside this mesh, return true. + return true; + } + } + + // It wasn't in any mesh, return false. + return false; +} + +QString HFMModel::getModelNameOfMesh(int meshIndex) const { + if (meshIndicesToModelNames.contains(meshIndex)) { + return meshIndicesToModelNames.value(meshIndex); + } + return QString(); +} diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h new file mode 100644 index 0000000000..7d4479e681 --- /dev/null +++ b/libraries/hfm/src/hfm/HFM.h @@ -0,0 +1,344 @@ +// +// HFM.h +// libraries/hfm/src +// +// Created by Sabrina Shanman on 2018/11/02. +// Copyright 2018 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_HFM_h_ +#define hifi_HFM_h_ + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; + +// High Fidelity Model namespace +namespace hfm { + +/// A single blendshape. +class Blendshape { +public: + QVector indices; + QVector vertices; + QVector normals; + QVector tangents; +}; + +struct JointShapeInfo { + // same units and frame as Joint.translation + glm::vec3 avgPoint; + std::vector dots; + std::vector points; + std::vector debugLines; +}; + +/// A single joint (transformation node). +class Joint { +public: + JointShapeInfo shapeInfo; + QVector freeLineage; + bool isFree; + int parentIndex; + float distanceToParent; + + // http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/SDKRef/a00209.html + + glm::vec3 translation; // T + glm::mat4 preTransform; // Roff * Rp + glm::quat preRotation; // Rpre + glm::quat rotation; // R + glm::quat postRotation; // Rpost + glm::mat4 postTransform; // Rp-1 * Soff * Sp * S * Sp-1 + + // World = ParentWorld * T * (Roff * Rp) * Rpre * R * Rpost * (Rp-1 * Soff * Sp * S * Sp-1) + + glm::mat4 transform; + glm::vec3 rotationMin; // radians + glm::vec3 rotationMax; // radians + glm::quat inverseDefaultRotation; + glm::quat inverseBindRotation; + glm::mat4 bindTransform; + QString name; + bool isSkeletonJoint; + bool bindTransformFoundInCluster; + + // geometric offset is applied in local space but does NOT affect children. + bool hasGeometricOffset; + glm::vec3 geometricTranslation; + glm::quat geometricRotation; + glm::vec3 geometricScaling; +}; + + +/// A single binding to a joint. +class Cluster { +public: + + int jointIndex; + glm::mat4 inverseBindMatrix; + Transform inverseBindTransform; +}; + +/// A texture map. +class Texture { +public: + QString id; + QString name; + QByteArray filename; + QByteArray content; + + Transform transform; + int maxNumPixels { MAX_NUM_PIXELS_FOR_FBX_TEXTURE }; + int texcoordSet; + QString texcoordSetName; + + bool isBumpmap{ false }; + + bool isNull() const { return name.isEmpty() && filename.isEmpty() && content.isEmpty(); } +}; + +/// A single part of a mesh (with the same material). +class MeshPart { +public: + + QVector quadIndices; // original indices from the FBX mesh + QVector quadTrianglesIndices; // original indices from the FBX mesh of the quad converted as triangles + QVector triangleIndices; // original indices from the FBX mesh + + QString materialID; +}; + +class Material { +public: + Material() {}; + Material(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor, + float shininess, float opacity) : + diffuseColor(diffuseColor), + specularColor(specularColor), + emissiveColor(emissiveColor), + shininess(shininess), + opacity(opacity) {} + + void getTextureNames(QSet& textureList) const; + void setMaxNumPixelsPerTexture(int maxNumPixels); + + glm::vec3 diffuseColor{ 1.0f }; + float diffuseFactor{ 1.0f }; + glm::vec3 specularColor{ 0.02f }; + float specularFactor{ 1.0f }; + + glm::vec3 emissiveColor{ 0.0f }; + float emissiveFactor{ 0.0f }; + + float shininess{ 23.0f }; + float opacity{ 1.0f }; + + float metallic{ 0.0f }; + float roughness{ 1.0f }; + float emissiveIntensity{ 1.0f }; + float ambientFactor{ 1.0f }; + + float bumpMultiplier { 1.0f }; // TODO: to be implemented + + QString materialID; + QString name; + QString shadingModel; + graphics::MaterialPointer _material; + + Texture normalTexture; + Texture albedoTexture; + Texture opacityTexture; + Texture glossTexture; + Texture roughnessTexture; + Texture specularTexture; + Texture metallicTexture; + Texture emissiveTexture; + Texture occlusionTexture; + Texture scatteringTexture; + Texture lightmapTexture; + glm::vec2 lightmapParams{ 0.0f, 1.0f }; + + + bool isPBSMaterial{ false }; + // THe use XXXMap are not really used to drive which map are going or not, debug only + bool useNormalMap{ false }; + bool useAlbedoMap{ false }; + bool useOpacityMap{ false }; + bool useRoughnessMap{ false }; + bool useSpecularMap{ false }; + bool useMetallicMap{ false }; + bool useEmissiveMap{ false }; + bool useOcclusionMap{ false }; + + bool needTangentSpace() const; +}; + +/// A single mesh (with optional blendshapes). +class Mesh { +public: + + QVector parts; + + QVector vertices; + QVector normals; + QVector tangents; + QVector colors; + QVector texCoords; + QVector texCoords1; + QVector clusterIndices; + QVector clusterWeights; + QVector originalIndices; + + QVector clusters; + + Extents meshExtents; + glm::mat4 modelTransform; + + QVector blendshapes; + + unsigned int meshIndex; // the order the meshes appeared in the object file + + graphics::MeshPointer _mesh; + bool wasCompressed { false }; + + void createMeshTangents(bool generateFromTexCoords); + void createBlendShapeTangents(bool generateTangents); +}; + +/**jsdoc + * @typedef {object} FBXAnimationFrame + * @property {Quat[]} rotations + * @property {Vec3[]} translations + */ +/// A single animation frame. +class AnimationFrame { +public: + QVector rotations; + QVector translations; +}; + +/// A light. +class Light { +public: + QString name; + Transform transform; + float intensity; + float fogValue; + glm::vec3 color; + + Light() : + name(), + transform(), + intensity(1.0f), + fogValue(0.0f), + color(1.0f) + {} +}; + +/// The runtime model format. +class Model { +public: + using Pointer = std::shared_ptr; + + QString originalURL; + QString author; + QString applicationName; ///< the name of the application that generated the model + + QVector joints; + QHash jointIndices; ///< 1-based, so as to more easily detect missing indices + bool hasSkeletonJoints; + + QVector meshes; + QVector scripts; + + QHash materials; + + glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file + + int leftEyeJointIndex = -1; + int rightEyeJointIndex = -1; + int neckJointIndex = -1; + int rootJointIndex = -1; + int leanJointIndex = -1; + int headJointIndex = -1; + int leftHandJointIndex = -1; + int rightHandJointIndex = -1; + int leftToeJointIndex = -1; + int rightToeJointIndex = -1; + + float leftEyeSize = 0.0f; // Maximum mesh extents dimension + float rightEyeSize = 0.0f; + + QVector humanIKJointIndices; + + glm::vec3 palmDirection; + + glm::vec3 neckPivot; + + Extents bindExtents; + Extents meshExtents; + + QVector animationFrames; + + int getJointIndex(const QString& name) const { return jointIndices.value(name) - 1; } + QStringList getJointNames() const; + + bool hasBlendedMeshes() const; + + /// Returns the unscaled extents of the model's mesh + Extents getUnscaledMeshExtents() const; + + bool convexHullContains(const glm::vec3& point) const; + + QHash meshIndicesToModelNames; + + /// given a meshIndex this will return the name of the model that mesh belongs to if known + QString getModelNameOfMesh(int meshIndex) const; + + QList blendshapeChannelNames; +}; + +}; + +class ExtractedMesh { +public: + hfm::Mesh mesh; + QMultiHash newIndices; + QVector > blendshapeIndexMaps; + QVector > partMaterialTextures; + QHash texcoordSetMap; +}; + +typedef hfm::Blendshape HFMBlendshape; +typedef hfm::JointShapeInfo HFMJointShapeInfo; +typedef hfm::Joint HFMJoint; +typedef hfm::Cluster HFMCluster; +typedef hfm::Texture HFMTexture; +typedef hfm::MeshPart HFMMeshPart; +typedef hfm::Material HFMMaterial; +typedef hfm::Mesh HFMMesh; +typedef hfm::AnimationFrame HFMAnimationFrame; +typedef hfm::Light HFMLight; +typedef hfm::Model HFMModel; + +Q_DECLARE_METATYPE(HFMAnimationFrame) +Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(HFMModel) +Q_DECLARE_METATYPE(HFMModel::Pointer) + +#endif // hifi_HFM_h_ diff --git a/libraries/fbx/src/ModelFormatLogging.cpp b/libraries/hfm/src/hfm/ModelFormatLogging.cpp similarity index 94% rename from libraries/fbx/src/ModelFormatLogging.cpp rename to libraries/hfm/src/hfm/ModelFormatLogging.cpp index e720b3c054..7748b8496d 100644 --- a/libraries/fbx/src/ModelFormatLogging.cpp +++ b/libraries/hfm/src/hfm/ModelFormatLogging.cpp @@ -1,6 +1,6 @@ // // ModelFormatLogging.cpp -// libraries/fbx/src +// libraries/hfm/src // // Created by Seth Alves on 4/6/15. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/fbx/src/ModelFormatLogging.h b/libraries/hfm/src/hfm/ModelFormatLogging.h similarity index 95% rename from libraries/fbx/src/ModelFormatLogging.h rename to libraries/hfm/src/hfm/ModelFormatLogging.h index 19c7c27322..745f22d7ff 100644 --- a/libraries/fbx/src/ModelFormatLogging.h +++ b/libraries/hfm/src/hfm/ModelFormatLogging.h @@ -1,6 +1,6 @@ // // ModelFormatLogging.h -// libraries/fbx/src +// libraries/hfm/src // // Created by Seth Alves on 4/6/15. // Copyright 2014 High Fidelity, Inc. diff --git a/libraries/model-networking/CMakeLists.txt b/libraries/model-networking/CMakeLists.txt index 12181651db..0fca6fa3d1 100644 --- a/libraries/model-networking/CMakeLists.txt +++ b/libraries/model-networking/CMakeLists.txt @@ -2,3 +2,4 @@ set(TARGET_NAME model-networking) setup_hifi_library() link_hifi_libraries(shared shaders networking graphics fbx ktx image gl) include_hifi_library_headers(gpu) +include_hifi_library_headers(hfm) diff --git a/libraries/render-utils/CMakeLists.txt b/libraries/render-utils/CMakeLists.txt index eaa3b4dbf5..2b092bff2a 100644 --- a/libraries/render-utils/CMakeLists.txt +++ b/libraries/render-utils/CMakeLists.txt @@ -7,6 +7,7 @@ link_hifi_libraries(shared task ktx gpu shaders graphics graphics-scripting mode include_hifi_library_headers(audio) include_hifi_library_headers(networking) include_hifi_library_headers(octree) +include_hifi_library_headers(hfm) # tell CMake to exclude qrc_fonts.cpp for policy CMP0071 set_property(SOURCE qrc_fonts.cpp PROPERTY SKIP_AUTOMOC ON) diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 588377c072..346c6e50f6 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -17,6 +17,6 @@ if (NOT ANDROID) endif () -link_hifi_libraries(shared networking octree shaders gpu procedural graphics model-networking ktx recording avatars fbx entities controllers animation audio physics image midi) +link_hifi_libraries(shared networking octree shaders gpu procedural graphics model-networking ktx recording avatars fbx hfm entities controllers animation audio physics image midi) # ui includes gl, but link_hifi_libraries does not use transitive includes, so gl must be explicit include_hifi_library_headers(gl) diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index 7c3671991e..8953ab7d27 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -11,7 +11,7 @@ if (WIN32 AND (NOT USE_GLES)) setup_hifi_plugin(Gui Qml Multimedia) link_hifi_libraries(shared task gl qml networking controllers ui plugins display-plugins ui-plugins input-plugins script-engine - audio-client render-utils graphics shaders gpu render model-networking fbx ktx image procedural ${PLATFORM_GL_BACKEND}) + audio-client render-utils graphics shaders gpu render model-networking hfm fbx ktx image procedural ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(octree) target_openvr() diff --git a/tests-manual/gpu/CMakeLists.txt b/tests-manual/gpu/CMakeLists.txt index 8fd0316c05..2b04bdc3f2 100644 --- a/tests-manual/gpu/CMakeLists.txt +++ b/tests-manual/gpu/CMakeLists.txt @@ -6,7 +6,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries( shared task networking gl ktx shaders gpu procedural octree image - graphics model-networking fbx animation + graphics model-networking fbx hfm animation script-engine render render-utils ${PLATFORM_GL_BACKEND} ) diff --git a/tests-manual/gpu/src/TestFbx.h b/tests-manual/gpu/src/TestFbx.h index 8056af21ec..9ca2c67c3b 100644 --- a/tests-manual/gpu/src/TestFbx.h +++ b/tests-manual/gpu/src/TestFbx.h @@ -11,8 +11,6 @@ #include -class HFMModel; - class TestFbx : public GpuTestBase { size_t _partCount { 0 }; graphics::Material _material; diff --git a/tests-manual/render-perf/CMakeLists.txt b/tests-manual/render-perf/CMakeLists.txt index 0cc3f87bd9..9e7d826d03 100644 --- a/tests-manual/render-perf/CMakeLists.txt +++ b/tests-manual/render-perf/CMakeLists.txt @@ -17,7 +17,7 @@ link_hifi_libraries( ktx image octree shaders gl gpu ${PLATFORM_GL_BACKEND} render render-utils - graphics fbx model-networking graphics-scripting + graphics hfm fbx model-networking graphics-scripting entities entities-renderer audio avatars script-engine physics procedural midi qml ui ${PLATFORM_GL_BACKEND} diff --git a/tests-manual/render-texture-load/CMakeLists.txt b/tests-manual/render-texture-load/CMakeLists.txt index 36526ecd42..af6c5b44b5 100644 --- a/tests-manual/render-texture-load/CMakeLists.txt +++ b/tests-manual/render-texture-load/CMakeLists.txt @@ -15,7 +15,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries( shared task networking octree shaders gl gpu render ktx image animation - graphics fbx model-networking + graphics hfm fbx model-networking render-utils entities entities-renderer audio avatars script-engine physics diff --git a/tools/oven/CMakeLists.txt b/tools/oven/CMakeLists.txt index 1b77a2585f..022c9769fe 100644 --- a/tools/oven/CMakeLists.txt +++ b/tools/oven/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME oven) setup_hifi_project(Widgets Gui Concurrent) -link_hifi_libraries(networking shared image gpu ktx fbx baking graphics) +link_hifi_libraries(networking shared image gpu ktx fbx hfm baking graphics) setup_memory_debugger() diff --git a/tools/skeleton-dump/CMakeLists.txt b/tools/skeleton-dump/CMakeLists.txt index d0a6475c59..baec1d163b 100644 --- a/tools/skeleton-dump/CMakeLists.txt +++ b/tools/skeleton-dump/CMakeLists.txt @@ -1,5 +1,4 @@ set(TARGET_NAME skeleton-dump) setup_hifi_project(Core) setup_memory_debugger() -link_hifi_libraries(shared fbx graphics gpu gl animation) - +link_hifi_libraries(shared fbx hfm graphics gpu gl animation) diff --git a/tools/vhacd-util/CMakeLists.txt b/tools/vhacd-util/CMakeLists.txt index 5ba8b7d971..aa6642c610 100644 --- a/tools/vhacd-util/CMakeLists.txt +++ b/tools/vhacd-util/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME vhacd-util) setup_hifi_project(Core) -link_hifi_libraries(shared fbx graphics gpu gl) +link_hifi_libraries(shared fbx hfm graphics gpu gl) add_dependency_external_projects(vhacd)