/*************************************************************************/ /* FBXDocument.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ /** @file FBXDocument.h * @brief FBX DOM */ #ifndef FBX_DOCUMENT_H #define FBX_DOCUMENT_H #include "FBXCommon.h" #include "FBXParser.h" #include "FBXProperties.h" #include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" #include "core/string/print_string.h" #include #include #define _AI_CONCAT(a, b) a##b #define AI_CONCAT(a, b) _AI_CONCAT(a, b) namespace FBXDocParser { class Parser; class Object; struct ImportSettings; class Connection; class PropertyTable; class Document; class Material; class ShapeGeometry; class LineGeometry; class Geometry; class Video; class AnimationCurve; class AnimationCurveNode; class AnimationLayer; class AnimationStack; class BlendShapeChannel; class BlendShape; class Skin; class Cluster; typedef Object *ObjectPtr; #define new_Object new Object /** Represents a delay-parsed FBX objects. Many objects in the scene * are not needed by assimp, so it makes no sense to parse them * upfront. */ class LazyObject { public: LazyObject(uint64_t id, const ElementPtr element, const Document &doc); ~LazyObject(); ObjectPtr LoadObject(); /* Casting weak pointers to their templated type safely and preserving ref counting and safety * with lock() keyword to prevent leaking memory */ template const T *Get() { ObjectPtr ob = LoadObject(); return dynamic_cast(ob); } uint64_t ID() const { return id; } bool IsBeingConstructed() const { return (flags & BEING_CONSTRUCTED) != 0; } bool FailedToConstruct() const { return (flags & FAILED_TO_CONSTRUCT) != 0; } ElementPtr GetElement() const { return element; } const Document &GetDocument() const { return doc; } private: const Document &doc; ElementPtr element = nullptr; std::shared_ptr object = nullptr; const uint64_t id = 0; enum Flags { BEING_CONSTRUCTED = 0x1, FAILED_TO_CONSTRUCT = 0x2 }; unsigned int flags = 0; }; /** Base class for in-memory (DOM) representations of FBX objects */ class Object : public PropertyTable { public: Object(uint64_t id, const ElementPtr element, const std::string &name); virtual ~Object(); ElementPtr SourceElement() const { return element; } const std::string &Name() const { return name; } uint64_t ID() const { return id; } protected: const ElementPtr element = nullptr; const std::string name; const uint64_t id; }; /** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table, * fixed members are added by deriving classes. */ class NodeAttribute : public Object { public: NodeAttribute(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~NodeAttribute(); }; /** DOM base class for FBX camera settings attached to a node */ class CameraSwitcher : public NodeAttribute { public: CameraSwitcher(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~CameraSwitcher(); int CameraID() const { return cameraId; } const std::string &CameraName() const { return cameraName; } const std::string &CameraIndexName() const { return cameraIndexName; } private: int cameraId = 0; std::string cameraName; std::string cameraIndexName; }; #define fbx_stringize(a) #a #define fbx_simple_property(name, type, default_value) \ type name() const { \ return PropertyGet(this, fbx_stringize(name), (default_value)); \ } // XXX improve logging #define fbx_simple_enum_property(name, type, default_value) \ type name() const { \ const int ival = PropertyGet(this, fbx_stringize(name), static_cast(default_value)); \ if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ return static_cast(default_value); \ } \ return static_cast(ival); \ } class FbxPoseNode; class FbxPose : public Object { public: FbxPose(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); const std::vector &GetBindPoses() const { return pose_nodes; } virtual ~FbxPose(); private: std::vector pose_nodes; }; class FbxPoseNode { public: FbxPoseNode(const ElementPtr element, const Document &doc, const std::string &name) { const ScopePtr sc = GetRequiredScope(element); // get pose node transform const ElementPtr Transform = GetRequiredElement(sc, "Matrix", element); transform = ReadMatrix(Transform); // get node id this pose node is for const ElementPtr NodeId = sc->GetElement("Node3D"); if (NodeId) { target_id = ParseTokenAsInt64(GetRequiredToken(NodeId, 0)); } print_verbose("added posenode " + itos(target_id) + " transform: " + transform); } virtual ~FbxPoseNode() { } uint64_t GetNodeID() const { return target_id; } Transform3D GetBindPose() const { return transform; } private: uint64_t target_id = 0; Transform3D transform; }; /** DOM base class for FBX cameras attached to a node */ class Camera : public NodeAttribute { public: Camera(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Camera(); fbx_simple_property(Position, Vector3, Vector3(0, 0, 0)); fbx_simple_property(UpVector, Vector3, Vector3(0, 1, 0)); fbx_simple_property(InterestPosition, Vector3, Vector3(0, 0, 0)); fbx_simple_property(AspectWidth, float, 1.0f); fbx_simple_property(AspectHeight, float, 1.0f); fbx_simple_property(FilmWidth, float, 1.0f); fbx_simple_property(FilmHeight, float, 1.0f); fbx_simple_property(NearPlane, float, 0.1f); fbx_simple_property(FarPlane, float, 100.0f); fbx_simple_property(FilmAspectRatio, float, 1.0f); fbx_simple_property(ApertureMode, int, 0); fbx_simple_property(FieldOfView, float, 1.0f); fbx_simple_property(FocalLength, float, 1.0f); }; /** DOM base class for FBX null markers attached to a node */ class Null : public NodeAttribute { public: Null(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Null(); }; /** DOM base class for FBX limb node markers attached to a node */ class LimbNode : public NodeAttribute { public: LimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~LimbNode(); }; /** DOM base class for FBX lights attached to a node */ class Light : public NodeAttribute { public: Light(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Light(); enum Type { Type_Point, Type_Directional, Type_Spot, Type_Area, Type_Volume, Type_MAX // end-of-enum sentinel }; enum Decay { Decay_None, Decay_Linear, Decay_Quadratic, Decay_Cubic, Decay_MAX // end-of-enum sentinel }; fbx_simple_property(Color, Vector3, Vector3(1, 1, 1)); fbx_simple_enum_property(LightType, Type, 0); fbx_simple_property(CastLightOnObject, bool, false); fbx_simple_property(DrawVolumetricLight, bool, true); fbx_simple_property(DrawGroundProjection, bool, true); fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false); fbx_simple_property(Intensity, float, 100.0f); fbx_simple_property(InnerAngle, float, 0.0f); fbx_simple_property(OuterAngle, float, 45.0f); fbx_simple_property(Fog, int, 50); fbx_simple_enum_property(DecayType, Decay, 2); fbx_simple_property(DecayStart, float, 1.0f); fbx_simple_property(FileName, std::string, ""); fbx_simple_property(EnableNearAttenuation, bool, false); fbx_simple_property(NearAttenuationStart, float, 0.0f); fbx_simple_property(NearAttenuationEnd, float, 0.0f); fbx_simple_property(EnableFarAttenuation, bool, false); fbx_simple_property(FarAttenuationStart, float, 0.0f); fbx_simple_property(FarAttenuationEnd, float, 0.0f); fbx_simple_property(CastShadows, bool, true); fbx_simple_property(ShadowColor, Vector3, Vector3(0, 0, 0)); fbx_simple_property(AreaLightShape, int, 0); fbx_simple_property(LeftBarnDoor, float, 20.0f); fbx_simple_property(RightBarnDoor, float, 20.0f); fbx_simple_property(TopBarnDoor, float, 20.0f); fbx_simple_property(BottomBarnDoor, float, 20.0f); fbx_simple_property(EnableBarnDoor, bool, true); }; class Model; typedef Model *ModelPtr; #define new_Model new Model /** DOM base class for FBX models (even though its semantics are more "node" than "model" */ class Model : public Object { public: enum RotOrder { RotOrder_EulerXYZ = 0, RotOrder_EulerXZY, RotOrder_EulerYZX, RotOrder_EulerYXZ, RotOrder_EulerZXY, RotOrder_EulerZYX, RotOrder_SphericXYZ, RotOrder_MAX // end-of-enum sentinel }; Model(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Model(); fbx_simple_property(QuaternionInterpolate, int, 0); fbx_simple_property(RotationOffset, Vector3, Vector3()); fbx_simple_property(RotationPivot, Vector3, Vector3()); fbx_simple_property(ScalingOffset, Vector3, Vector3()); fbx_simple_property(ScalingPivot, Vector3, Vector3()); fbx_simple_property(TranslationActive, bool, false); fbx_simple_property(TranslationMin, Vector3, Vector3()); fbx_simple_property(TranslationMax, Vector3, Vector3()); fbx_simple_property(TranslationMinX, bool, false); fbx_simple_property(TranslationMaxX, bool, false); fbx_simple_property(TranslationMinY, bool, false); fbx_simple_property(TranslationMaxY, bool, false); fbx_simple_property(TranslationMinZ, bool, false); fbx_simple_property(TranslationMaxZ, bool, false); fbx_simple_enum_property(RotationOrder, RotOrder, 0); fbx_simple_property(RotationSpaceForLimitOnly, bool, false); fbx_simple_property(RotationStiffnessX, float, 0.0f); fbx_simple_property(RotationStiffnessY, float, 0.0f); fbx_simple_property(RotationStiffnessZ, float, 0.0f); fbx_simple_property(AxisLen, float, 0.0f); fbx_simple_property(PreRotation, Vector3, Vector3()); fbx_simple_property(PostRotation, Vector3, Vector3()); fbx_simple_property(RotationActive, bool, false); fbx_simple_property(RotationMin, Vector3, Vector3()); fbx_simple_property(RotationMax, Vector3, Vector3()); fbx_simple_property(RotationMinX, bool, false); fbx_simple_property(RotationMaxX, bool, false); fbx_simple_property(RotationMinY, bool, false); fbx_simple_property(RotationMaxY, bool, false); fbx_simple_property(RotationMinZ, bool, false); fbx_simple_property(RotationMaxZ, bool, false); fbx_simple_enum_property(InheritType, TransformInheritance, 0); fbx_simple_property(ScalingActive, bool, false); fbx_simple_property(ScalingMin, Vector3, Vector3()); fbx_simple_property(ScalingMax, Vector3, Vector3(1, 1, 1)); fbx_simple_property(ScalingMinX, bool, false); fbx_simple_property(ScalingMaxX, bool, false); fbx_simple_property(ScalingMinY, bool, false); fbx_simple_property(ScalingMaxY, bool, false); fbx_simple_property(ScalingMinZ, bool, false); fbx_simple_property(ScalingMaxZ, bool, false); fbx_simple_property(GeometricTranslation, Vector3, Vector3()); fbx_simple_property(GeometricRotation, Vector3, Vector3()); fbx_simple_property(GeometricScaling, Vector3, Vector3(1, 1, 1)); fbx_simple_property(MinDampRangeX, float, 0.0f); fbx_simple_property(MinDampRangeY, float, 0.0f); fbx_simple_property(MinDampRangeZ, float, 0.0f); fbx_simple_property(MaxDampRangeX, float, 0.0f); fbx_simple_property(MaxDampRangeY, float, 0.0f); fbx_simple_property(MaxDampRangeZ, float, 0.0f); fbx_simple_property(MinDampStrengthX, float, 0.0f); fbx_simple_property(MinDampStrengthY, float, 0.0f); fbx_simple_property(MinDampStrengthZ, float, 0.0f); fbx_simple_property(MaxDampStrengthX, float, 0.0f); fbx_simple_property(MaxDampStrengthY, float, 0.0f); fbx_simple_property(MaxDampStrengthZ, float, 0.0f); fbx_simple_property(PreferredAngleX, float, 0.0f); fbx_simple_property(PreferredAngleY, float, 0.0f); fbx_simple_property(PreferredAngleZ, float, 0.0f); fbx_simple_property(Show, bool, true); fbx_simple_property(LODBox, bool, false); fbx_simple_property(Freeze, bool, false); const std::string &Shading() const { return shading; } const std::string &Culling() const { return culling; } /** Get material links */ const std::vector &GetMaterials() const { return materials; } /** Get geometry links */ const std::vector &GetGeometry() const { return geometry; } /** Get node attachments */ const std::vector &GetAttributes() const { return attributes; } /** convenience method to check if the node has a Null node marker */ bool IsNull() const; private: void ResolveLinks(const ElementPtr element, const Document &doc); private: std::vector materials; std::vector geometry; std::vector attributes; std::string shading; std::string culling; }; class ModelLimbNode : public Model { public: ModelLimbNode(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~ModelLimbNode(); }; /** DOM class for generic FBX textures */ class Texture : public Object { public: Texture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Texture(); const std::string &Type() const { return type; } const std::string &FileName() const { return fileName; } const std::string &RelativeFilename() const { return relativeFileName; } const std::string &AlphaSource() const { return alphaSource; } const Vector2 &UVTranslation() const { return uvTrans; } const Vector2 &UVScaling() const { return uvScaling; } // return a 4-tuple const unsigned int *Crop() const { return crop; } const Video *Media() const { return media; } private: Vector2 uvTrans; Vector2 uvScaling; std::string type; std::string relativeFileName; std::string fileName; std::string alphaSource; unsigned int crop[4] = { 0 }; const Video *media = nullptr; }; /** DOM class for layered FBX textures */ class LayeredTexture : public Object { public: LayeredTexture(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~LayeredTexture(); // Can only be called after construction of the layered texture object due to construction flag. void fillTexture(const Document &doc); enum BlendMode { BlendMode_Translucent, BlendMode_Additive, BlendMode_Modulate, BlendMode_Modulate2, BlendMode_Over, BlendMode_Normal, BlendMode_Dissolve, BlendMode_Darken, BlendMode_ColorBurn, BlendMode_LinearBurn, BlendMode_DarkerColor, BlendMode_Lighten, BlendMode_Screen, BlendMode_ColorDodge, BlendMode_LinearDodge, BlendMode_LighterColor, BlendMode_SoftLight, BlendMode_HardLight, BlendMode_VividLight, BlendMode_LinearLight, BlendMode_PinLight, BlendMode_HardMix, BlendMode_Difference, BlendMode_Exclusion, BlendMode_Subtract, BlendMode_Divide, BlendMode_Hue, BlendMode_Saturation, BlendMode_Color, BlendMode_Luminosity, BlendMode_Overlay, BlendMode_BlendModeCount }; const Texture *getTexture(int index = 0) const { return textures[index]; } int textureCount() const { return static_cast(textures.size()); } BlendMode GetBlendMode() const { return blendMode; } float Alpha() { return alpha; } private: std::vector textures; BlendMode blendMode = BlendMode::BlendMode_Additive; float alpha = 0; }; typedef std::map TextureMap; typedef std::map LayeredTextureMap; /** DOM class for generic FBX videos */ class Video : public Object { public: Video(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Video(); const std::string &Type() const { return type; } bool IsEmbedded() const { return contentLength > 0; } const std::string &FileName() const { return fileName; } const std::string &RelativeFilename() const { return relativeFileName; } const uint8_t *Content() const { return content; } uint64_t ContentLength() const { return contentLength; } uint8_t *RelinquishContent() { uint8_t *ptr = content; content = nullptr; return ptr; } bool operator==(const Video &other) const { return ( type == other.type && relativeFileName == other.relativeFileName && fileName == other.fileName); } bool operator<(const Video &other) const { return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName); } private: std::string type; std::string relativeFileName; std::string fileName; uint64_t contentLength = 0; uint8_t *content = nullptr; }; /** DOM class for generic FBX materials */ class Material : public Object { public: Material(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Material(); const std::string &GetShadingModel() const { return shading; } bool IsMultilayer() const { return multilayer; } const TextureMap &Textures() const { return textures; } const LayeredTextureMap &LayeredTextures() const { return layeredTextures; } private: std::string shading; bool multilayer = false; TextureMap textures; LayeredTextureMap layeredTextures; }; // signed int keys (this can happen!) typedef std::vector KeyTimeList; typedef std::vector KeyValueList; /** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefore) */ class AnimationCurve : public Object { public: AnimationCurve(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); virtual ~AnimationCurve(); /** get list of keyframe positions (time). * Invariant: |GetKeys()| > 0 */ const KeyTimeList &GetKeys() const { return keys; } /** get list of keyframe values. * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/ const KeyValueList &GetValues() const { return values; } const std::map &GetValueTimeTrack() const { return keyvalues; } const std::vector &GetAttributes() const { return attributes; } const std::vector &GetFlags() const { return flags; } private: KeyTimeList keys; KeyValueList values; std::vector attributes; std::map keyvalues; std::vector flags; }; /* Typedef for pointers for the animation handler */ typedef std::shared_ptr AnimationCurvePtr; typedef std::weak_ptr AnimationCurveWeakPtr; typedef std::map AnimationMap; /* Animation Curve node ptr */ typedef std::shared_ptr AnimationCurveNodePtr; typedef std::weak_ptr AnimationCurveNodeWeakPtr; /** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */ class AnimationCurveNode : public Object { public: /* the optional white list specifies a list of property names for which the caller wants animations for. If the curve node does not match one of these, std::range_error will be thrown. */ AnimationCurveNode(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc, const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0); virtual ~AnimationCurveNode(); const AnimationMap &Curves() const; /** Object the curve is assigned to, this can be nullptr if the * target object has no DOM representation or could not * be read for other reasons.*/ Object *Target() const { return target; } Model *TargetAsModel() const { return dynamic_cast(target); } NodeAttribute *TargetAsNodeAttribute() const { return dynamic_cast(target); } /** Property of Target() that is being animated*/ const std::string &TargetProperty() const { return prop; } private: Object *target = nullptr; mutable AnimationMap curves; std::string prop; const Document &doc; }; typedef std::vector AnimationCurveNodeList; typedef std::shared_ptr AnimationLayerPtr; typedef std::weak_ptr AnimationLayerWeakPtr; typedef std::vector AnimationLayerList; /** Represents a FBX animation layer (i.e. a list of node animations) */ class AnimationLayer : public Object { public: AnimationLayer(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); virtual ~AnimationLayer(); /* the optional white list specifies a list of property names for which the caller wants animations for. Curves not matching this list will not be added to the animation layer. */ const AnimationCurveNodeList Nodes(const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0) const; private: const Document &doc; }; /** Represents a FBX animation stack (i.e. a list of animation layers) */ class AnimationStack : public Object { public: AnimationStack(uint64_t id, const ElementPtr element, const std::string &name, const Document &doc); virtual ~AnimationStack(); fbx_simple_property(LocalStart, int64_t, 0L); fbx_simple_property(LocalStop, int64_t, 0L); fbx_simple_property(ReferenceStart, int64_t, 0L); fbx_simple_property(ReferenceStop, int64_t, 0L); const AnimationLayerList &Layers() const { return layers; } private: AnimationLayerList layers; }; /** DOM class for deformers */ class Deformer : public Object { public: Deformer(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Deformer(); }; /** Constraints are from Maya they can help us with BoneAttachments :) **/ class Constraint : public Object { public: Constraint(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Constraint(); }; typedef std::vector WeightArray; typedef std::vector WeightIndexArray; /** DOM class for BlendShapeChannel deformers */ class BlendShapeChannel : public Deformer { public: BlendShapeChannel(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~BlendShapeChannel(); float DeformPercent() const { return percent; } const WeightArray &GetFullWeights() const { return fullWeights; } const std::vector &GetShapeGeometries() const { return shapeGeometries; } private: float percent = 0; WeightArray fullWeights; std::vector shapeGeometries; }; /** DOM class for BlendShape deformers */ class BlendShape : public Deformer { public: BlendShape(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~BlendShape(); const std::vector &BlendShapeChannels() const { return blendShapeChannels; } private: std::vector blendShapeChannels; }; /** DOM class for skin deformer clusters (aka sub-deformers) */ class Cluster : public Deformer { public: Cluster(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Cluster(); /** get the list of deformer weights associated with this cluster. * Use #GetIndices() to get the associated vertices. Both arrays * have the same size (and may also be empty). */ const std::vector &GetWeights() const { return weights; } /** get indices into the vertex data of the geometry associated * with this cluster. Use #GetWeights() to get the associated weights. * Both arrays have the same size (and may also be empty). */ const std::vector &GetIndices() const { return indices; } /** */ const Transform3D &GetTransform() const { return transform; } const Transform3D &TransformLink() const { return transformLink; } const Model *TargetNode() const { return node; } const Transform3D &TransformAssociateModel() const { return transformAssociateModel; } bool TransformAssociateModelValid() const { return valid_transformAssociateModel; } // property is not in the fbx file // if the cluster has an associate model // we then have an additive type enum SkinLinkMode { SkinLinkMode_Normalized = 0, SkinLinkMode_Additive = 1 }; SkinLinkMode GetLinkMode() { return link_mode; } private: std::vector weights; std::vector indices; Transform3D transform; Transform3D transformLink; Transform3D transformAssociateModel; SkinLinkMode link_mode; bool valid_transformAssociateModel = false; const Model *node = nullptr; }; /** DOM class for skin deformers */ class Skin : public Deformer { public: Skin(uint64_t id, const ElementPtr element, const Document &doc, const std::string &name); virtual ~Skin(); float DeformAccuracy() const { return accuracy; } const std::vector &Clusters() const { return clusters; } enum SkinType { Skin_Rigid = 0, Skin_Linear, Skin_DualQuaternion, Skin_Blend }; const SkinType &GetSkinType() const { return skinType; } private: float accuracy = 0; SkinType skinType = SkinType::Skin_Linear; std::vector clusters; }; /** Represents a link between two FBX objects. */ class Connection { public: Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string &prop, const Document &doc); ~Connection(); // note: a connection ensures that the source and dest objects exist, but // not that they have DOM representations, so the return value of one of // these functions can still be nullptr. Object *SourceObject() const; Object *DestinationObject() const; // these, however, are always guaranteed to be valid LazyObject *LazySourceObject() const; LazyObject *LazyDestinationObject() const; /** return the name of the property the connection is attached to. * this is an empty string for object to object (OO) connections. */ const std::string &PropertyName() const { return prop; } uint64_t InsertionOrder() const { return insertionOrder; } int CompareTo(const Connection *c) const { //ai_assert(nullptr != c); // note: can't subtract because this would overflow uint64_t if (InsertionOrder() > c->InsertionOrder()) { return 1; } else if (InsertionOrder() < c->InsertionOrder()) { return -1; } return 0; } bool Compare(const Connection *c) const { //ai_assert(nullptr != c); return InsertionOrder() < c->InsertionOrder(); } public: uint64_t insertionOrder = 0; const std::string prop; uint64_t src = 0, dest = 0; const Document &doc; }; // XXX again, unique_ptr would be useful. shared_ptr is too // bloated since the objects have a well-defined single owner // during their entire lifetime (Document). FBX files have // up to many thousands of objects (most of which we never use), // so the memory overhead for them should be kept at a minimum. typedef std::map ObjectMap; typedef std::map PropertyTemplateMap; typedef std::multimap ConnectionMap; /** DOM class for global document settings, a single instance per document can * be accessed via Document.Globals(). */ class FileGlobalSettings : public PropertyTable { public: FileGlobalSettings(const Document &doc); virtual ~FileGlobalSettings(); const Document &GetDocument() const { return doc; } fbx_simple_property(UpAxis, int, 1); fbx_simple_property(UpAxisSign, int, 1); fbx_simple_property(FrontAxis, int, 2); fbx_simple_property(FrontAxisSign, int, 1); fbx_simple_property(CoordAxis, int, 0); fbx_simple_property(CoordAxisSign, int, 1); fbx_simple_property(OriginalUpAxis, int, 0); fbx_simple_property(OriginalUpAxisSign, int, 1); fbx_simple_property(UnitScaleFactor, float, 1); fbx_simple_property(OriginalUnitScaleFactor, float, 1); fbx_simple_property(AmbientColor, Vector3, Vector3(0, 0, 0)); fbx_simple_property(DefaultCamera, std::string, ""); enum FrameRate { FrameRate_DEFAULT = 0, FrameRate_120 = 1, FrameRate_100 = 2, FrameRate_60 = 3, FrameRate_50 = 4, FrameRate_48 = 5, FrameRate_30 = 6, FrameRate_30_DROP = 7, FrameRate_NTSC_DROP_FRAME = 8, FrameRate_NTSC_FULL_FRAME = 9, FrameRate_PAL = 10, FrameRate_CINEMA = 11, FrameRate_1000 = 12, FrameRate_CINEMA_ND = 13, FrameRate_CUSTOM = 14, FrameRate_MAX // end-of-enum sentinel }; fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT); fbx_simple_property(TimeSpanStart, uint64_t, 0L); fbx_simple_property(TimeSpanStop, uint64_t, 0L); fbx_simple_property(CustomFrameRate, float, -1.0f); private: const Document &doc; }; /** DOM root for a FBX file */ class Document { public: Document(const Parser &parser, const ImportSettings &settings); ~Document(); LazyObject *GetObject(uint64_t id) const; bool IsSafeToImport() const { return SafeToImport; } bool IsBinary() const { return parser.IsBinary(); } unsigned int FBXVersion() const { return fbxVersion; } const std::string &Creator() const { return creator; } // elements (in this order): Year, Month, Day, Hour, Second, Millisecond const unsigned int *CreationTimeStamp() const { return creationTimeStamp; } const FileGlobalSettings *GlobalSettingsPtr() const { return globals.get(); } const PropertyTable &GetMetadataProperties() const { return metadata_properties; } const PropertyTemplateMap &Templates() const { return templates; } const ObjectMap &Objects() const { return objects; } const ImportSettings &Settings() const { return settings; } const ConnectionMap &ConnectionsBySource() const { return src_connections; } const ConnectionMap &ConnectionsByDestination() const { return dest_connections; } // note: the implicit rule in all DOM classes is to always resolve // from destination to source (since the FBX object hierarchy is, // with very few exceptions, a DAG, this avoids cycles). In all // cases that may involve back-facing edges in the object graph, // use LazyObject::IsBeingConstructed() to check. std::vector GetConnectionsBySourceSequenced(uint64_t source) const; std::vector GetConnectionsByDestinationSequenced(uint64_t dest) const; std::vector GetConnectionsBySourceSequenced(uint64_t source, const char *classname) const; std::vector GetConnectionsByDestinationSequenced(uint64_t dest, const char *classname) const; std::vector GetConnectionsBySourceSequenced(uint64_t source, const char *const *classnames, size_t count) const; std::vector GetConnectionsByDestinationSequenced(uint64_t dest, const char *const *classnames, size_t count) const; const std::vector &AnimationStacks() const; const std::vector &GetAnimationStackIDs() const { return animationStacks; } const std::vector &GetConstraintStackIDs() const { return constraints; } const std::vector &GetBindPoseIDs() const { return bind_poses; }; const std::vector &GetMaterialIDs() const { return materials; }; const std::vector &GetSkinIDs() const { return skins; } private: std::vector GetConnectionsSequenced(uint64_t id, const ConnectionMap &) const; std::vector GetConnectionsSequenced(uint64_t id, bool is_src, const ConnectionMap &, const char *const *classnames, size_t count) const; bool ReadHeader(); void ReadObjects(); void ReadPropertyTemplates(); void ReadConnections(); void ReadGlobalSettings(); private: const ImportSettings &settings; ObjectMap objects; const Parser &parser; bool SafeToImport = false; PropertyTemplateMap templates; ConnectionMap src_connections; ConnectionMap dest_connections; unsigned int fbxVersion = 0; std::string creator; unsigned int creationTimeStamp[7] = { 0 }; std::vector animationStacks; std::vector bind_poses; // constraints aren't in the tree / at least they are not easy to access. std::vector constraints; std::vector materials; std::vector skins; mutable std::vector animationStacksResolved; PropertyTable metadata_properties; std::shared_ptr globals = nullptr; }; } // namespace FBXDocParser namespace std { template <> struct hash { std::size_t operator()(const FBXDocParser::Video &video) const { using std::hash; using std::size_t; using std::string; size_t res = 17; res = res * 31 + hash()(video.Name()); res = res * 31 + hash()(video.RelativeFilename()); res = res * 31 + hash()(video.Type()); return res; } }; } // namespace std #endif // FBX_DOCUMENT_H