fe52458154
Happy new year to the wonderful Godot community!
1253 lines
34 KiB
C++
1253 lines
34 KiB
C++
/*************************************************************************/
|
|
/* 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 <stdint.h>
|
|
#include <numeric>
|
|
|
|
#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 <typename T>
|
|
const T *Get() {
|
|
ObjectPtr ob = LoadObject();
|
|
return dynamic_cast<const T *>(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> 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<type>(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<int>(this, fbx_stringize(name), static_cast<int>(default_value)); \
|
|
if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \
|
|
return static_cast<type>(default_value); \
|
|
} \
|
|
return static_cast<type>(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<FbxPoseNode *> &GetBindPoses() const {
|
|
return pose_nodes;
|
|
}
|
|
|
|
virtual ~FbxPose();
|
|
|
|
private:
|
|
std::vector<FbxPoseNode *> 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<const Material *> &GetMaterials() const {
|
|
return materials;
|
|
}
|
|
|
|
/** Get geometry links */
|
|
const std::vector<const Geometry *> &GetGeometry() const {
|
|
return geometry;
|
|
}
|
|
|
|
/** Get node attachments */
|
|
const std::vector<const NodeAttribute *> &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<const Material *> materials;
|
|
std::vector<const Geometry *> geometry;
|
|
std::vector<const NodeAttribute *> 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<int>(textures.size());
|
|
}
|
|
BlendMode GetBlendMode() const {
|
|
return blendMode;
|
|
}
|
|
float Alpha() {
|
|
return alpha;
|
|
}
|
|
|
|
private:
|
|
std::vector<const Texture *> textures;
|
|
BlendMode blendMode = BlendMode::BlendMode_Additive;
|
|
float alpha = 0;
|
|
};
|
|
|
|
typedef std::map<std::string, const Texture *> TextureMap;
|
|
typedef std::map<std::string, const LayeredTexture *> 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<int64_t> KeyTimeList;
|
|
typedef std::vector<float> 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<int64_t, float> &GetValueTimeTrack() const {
|
|
return keyvalues;
|
|
}
|
|
|
|
const std::vector<float> &GetAttributes() const {
|
|
return attributes;
|
|
}
|
|
|
|
const std::vector<unsigned int> &GetFlags() const {
|
|
return flags;
|
|
}
|
|
|
|
private:
|
|
KeyTimeList keys;
|
|
KeyValueList values;
|
|
std::vector<float> attributes;
|
|
std::map<int64_t, float> keyvalues;
|
|
std::vector<unsigned int> flags;
|
|
};
|
|
|
|
/* Typedef for pointers for the animation handler */
|
|
typedef std::shared_ptr<AnimationCurve> AnimationCurvePtr;
|
|
typedef std::weak_ptr<AnimationCurve> AnimationCurveWeakPtr;
|
|
typedef std::map<std::string, const AnimationCurve *> AnimationMap;
|
|
|
|
/* Animation Curve node ptr */
|
|
typedef std::shared_ptr<AnimationCurveNode> AnimationCurveNodePtr;
|
|
typedef std::weak_ptr<AnimationCurveNode> 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<Model *>(target);
|
|
}
|
|
|
|
NodeAttribute *TargetAsNodeAttribute() const {
|
|
return dynamic_cast<NodeAttribute *>(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<const AnimationCurveNode *> AnimationCurveNodeList;
|
|
|
|
typedef std::shared_ptr<AnimationLayer> AnimationLayerPtr;
|
|
typedef std::weak_ptr<AnimationLayer> AnimationLayerWeakPtr;
|
|
typedef std::vector<const AnimationLayer *> 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<float> WeightArray;
|
|
typedef std::vector<unsigned int> 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<const ShapeGeometry *> &GetShapeGeometries() const {
|
|
return shapeGeometries;
|
|
}
|
|
|
|
private:
|
|
float percent = 0;
|
|
WeightArray fullWeights;
|
|
std::vector<const ShapeGeometry *> 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<const BlendShapeChannel *> &BlendShapeChannels() const {
|
|
return blendShapeChannels;
|
|
}
|
|
|
|
private:
|
|
std::vector<const BlendShapeChannel *> 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<float> &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<unsigned int> &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<float> weights;
|
|
std::vector<unsigned int> 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<const Cluster *> &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<const Cluster *> 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<uint64_t, LazyObject *> ObjectMap;
|
|
typedef std::map<std::string, const PropertyTable *> PropertyTemplateMap;
|
|
typedef std::multimap<uint64_t, const Connection *> 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<const Connection *> GetConnectionsBySourceSequenced(uint64_t source) const;
|
|
std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest) const;
|
|
|
|
std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source, const char *classname) const;
|
|
std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest, const char *classname) const;
|
|
|
|
std::vector<const Connection *> GetConnectionsBySourceSequenced(uint64_t source,
|
|
const char *const *classnames, size_t count) const;
|
|
std::vector<const Connection *> GetConnectionsByDestinationSequenced(uint64_t dest,
|
|
const char *const *classnames,
|
|
size_t count) const;
|
|
|
|
const std::vector<const AnimationStack *> &AnimationStacks() const;
|
|
const std::vector<uint64_t> &GetAnimationStackIDs() const {
|
|
return animationStacks;
|
|
}
|
|
|
|
const std::vector<uint64_t> &GetConstraintStackIDs() const {
|
|
return constraints;
|
|
}
|
|
|
|
const std::vector<uint64_t> &GetBindPoseIDs() const {
|
|
return bind_poses;
|
|
};
|
|
|
|
const std::vector<uint64_t> &GetMaterialIDs() const {
|
|
return materials;
|
|
};
|
|
|
|
const std::vector<uint64_t> &GetSkinIDs() const {
|
|
return skins;
|
|
}
|
|
|
|
private:
|
|
std::vector<const Connection *> GetConnectionsSequenced(uint64_t id, const ConnectionMap &) const;
|
|
std::vector<const Connection *> 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<uint64_t> animationStacks;
|
|
std::vector<uint64_t> bind_poses;
|
|
// constraints aren't in the tree / at least they are not easy to access.
|
|
std::vector<uint64_t> constraints;
|
|
std::vector<uint64_t> materials;
|
|
std::vector<uint64_t> skins;
|
|
mutable std::vector<const AnimationStack *> animationStacksResolved;
|
|
PropertyTable metadata_properties;
|
|
std::shared_ptr<FileGlobalSettings> globals = nullptr;
|
|
};
|
|
} // namespace FBXDocParser
|
|
|
|
namespace std {
|
|
template <>
|
|
struct hash<const FBXDocParser::Video> {
|
|
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<string>()(video.Name());
|
|
res = res * 31 + hash<string>()(video.RelativeFilename());
|
|
res = res * 31 + hash<string>()(video.Type());
|
|
|
|
return res;
|
|
}
|
|
};
|
|
} // namespace std
|
|
|
|
#endif // FBX_DOCUMENT_H
|