// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#if COMPILE_WITH_MODEL_TOOL
#include "Engine/Core/Config.h"
#include "Engine/Serialization/ISerializable.h"
#include "Engine/Graphics/Models/ModelData.h"
#include "Engine/Graphics/Models/SkeletonData.h"
#include "Engine/Animations/AnimationData.h"
class JsonWriter;
///
/// The model file import data types (used as flags).
///
enum class ImportDataTypes : int32
{
///
/// Imports materials and meshes.
///
Geometry = 1 << 0,
///
/// Imports the skeleton bones hierarchy.
///
Skeleton = 1 << 1,
///
/// Imports the animations.
///
Animations = 1 << 2,
///
/// Imports the scene nodes hierarchy.
///
Nodes = 1 << 3,
///
/// Imports the materials.
///
Materials = 1 << 4,
///
/// Imports the textures.
///
Textures = 1 << 5,
};
DECLARE_ENUM_OPERATORS(ImportDataTypes);
///
/// Imported model data container. Represents unified model source file data (meshes, animations, skeleton, materials).
///
class ImportedModelData
{
public:
struct LOD
{
Array Meshes;
BoundingBox GetBox() const;
};
struct Node
{
///
/// The parent node index. The root node uses value -1.
///
int32 ParentIndex;
///
/// The local transformation of the node, relative to the parent node.
///
Transform LocalTransform;
///
/// The name of this node.
///
String Name;
};
public:
///
/// The import data types types.
///
ImportDataTypes Types;
///
/// The textures slots.
///
Array Textures;
///
/// The material slots.
///
Array Materials;
///
/// The level of details data.
///
Array LODs;
///
/// The skeleton data.
///
SkeletonData Skeleton;
///
/// The scene nodes.
///
Array Nodes;
///
/// The node animations.
///
AnimationData Animation;
public:
///
/// Initializes a new instance of the class.
///
/// The types.
ImportedModelData(ImportDataTypes types)
{
Types = types;
}
///
/// Finalizes an instance of the class.
///
~ImportedModelData()
{
// Ensure to cleanup data
for (int32 i = 0; i < LODs.Count(); i++)
LODs[i].Meshes.ClearDelete();
}
};
///
/// Import models and animations helper.
///
class FLAXENGINE_API ModelTool
{
public:
///
/// Declares the imported data type.
///
DECLARE_ENUM_EX_3(ModelType, int32, 0, Model, SkinnedModel, Animation);
///
/// Declares the imported animation clip duration.
///
DECLARE_ENUM_EX_2(AnimationDuration, int32, 0, Imported, Custom);
///
/// Importing model options
///
struct Options : public ISerializable
{
ModelType Type = ModelType::Model;
// Geometry
bool CalculateNormals = false;
float SmoothingNormalsAngle = 175.0f;
bool FlipNormals = false;
float SmoothingTangentsAngle = 45.0f;
bool CalculateTangents = true;
bool OptimizeMeshes = true;
bool MergeMeshes = true;
bool ImportLODs = true;
bool ImportVertexColors = true;
bool ImportBlendShapes = false;
ModelLightmapUVsSource LightmapUVsSource = ModelLightmapUVsSource::Disable;
// Transform
float Scale = 1.0f;
Quaternion Rotation = Quaternion::Identity;
Vector3 Translation = Vector3::Zero;
bool CenterGeometry = false;
// Animation
AnimationDuration Duration = AnimationDuration::Imported;
Vector2 FramesRange = Vector2::Zero;
float DefaultFrameRate = 0.0f;
float SamplingRate = 0.0f;
bool SkipEmptyCurves = true;
bool OptimizeKeyframes = true;
bool EnableRootMotion = false;
String RootNodeName;
int32 AnimationIndex = -1;
// Level Of Detail
bool GenerateLODs = false;
int32 BaseLOD = 0;
int32 LODCount = 4;
float TriangleReduction = 0.5f;
// Materials
bool ImportMaterials = true;
bool ImportTextures = true;
bool RestoreMaterialsOnReimport = true;
public:
// [ISerializable]
void Serialize(SerializeStream& stream, const void* otherObj) override;
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override;
};
public:
///
/// Imports the model source file data.
///
/// The file path.
/// The output data.
/// The import options.
/// The error message container.
/// True if fails, otherwise false.
static bool ImportData(const String& path, ImportedModelData& data, Options options, String& errorMsg);
///
/// Imports the model.
///
/// The file path.
/// The output data.
/// The import options.
/// The error message container.
/// The output folder for the additional imported data - optional. Used to auto-import textures and material assets.
/// True if fails, otherwise false.
static bool ImportModel(const String& path, ModelData& meshData, Options options, String& errorMsg, const String& autoImportOutput = String::Empty);
public:
static int32 DetectLodIndex(const String& nodeName);
static bool FindTexture(const String& sourcePath, const String& file, String& path);
///
/// Gets the local transformations to go from rootIndex to index.
///
/// The nodes containing the local transformations.
/// The root index.
/// The current index.
/// The transformation at this index.
template
static Transform CombineTransformsFromNodeIndices(Array& nodes, int32 rootIndex, int32 index)
{
if (index == -1 || index == rootIndex)
return Transform::Identity;
auto result = nodes[index].LocalTransform;
if (index != rootIndex)
{
const auto parentTransform = CombineTransformsFromNodeIndices(nodes, rootIndex, nodes[index].ParentIndex);
result = parentTransform.LocalToWorld(result);
}
return result;
}
private:
#if USE_ASSIMP
static bool ImportDataAssimp(const char* path, ImportedModelData& data, const Options& options, String& errorMsg);
#endif
#if USE_AUTODESK_FBX_SDK
static bool ImportDataAutodeskFbxSdk(const char* path, ImportedModelData& data, const Options& options, String& errorMsg);
#endif
#if USE_OPEN_FBX
static bool ImportDataOpenFBX(const char* path, ImportedModelData& data, const Options& options, String& errorMsg);
#endif
};
#endif