// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Types/Guid.h"
#include "Engine/Graphics/Enums.h"
#include "Types.h"
#include "Config.h"
#include "SkeletonData.h"
#include "BlendShape.h"
#include "Engine/Animations/AnimationData.h"
class WriteStream;
///
/// Data container for the common model meshes data. Supports holding all types of data related to the models pipeline.
///
class FLAXENGINE_API MeshData
{
public:
///
/// The slot index in the model materials to use during rendering.
///
int32 MaterialSlotIndex = 0;
///
/// The model skeleton node index. Used during importing and by the animated models.
///
int32 NodeIndex = 0;
///
/// The name of the mesh.
///
String Name;
///
/// Mesh positions buffer
///
Array Positions;
///
/// Texture coordinates
///
Array UVs;
///
/// Normals vector
///
Array Normals;
///
/// Tangents vectors
///
Array Tangents;
///
/// Bitangents vectors signs (used for bitangent reconstruction). Can be +1 or -1.
/// bitangent = cross(normal, tangent) * sign
/// sign = dot(cross(bitangent, normal), tangent)
///
Array BitangentSigns;
///
/// Mesh index buffer
///
Array Indices;
///
/// Lightmap UVs
///
Array LightmapUVs;
///
/// Vertex colors
///
Array Colors;
///
/// Skinned mesh blend indices (max 4 per bone)
///
Array BlendIndices;
///
/// Skinned mesh index buffer (max 4 per bone)
///
Array BlendWeights;
///
/// Blend shapes used by this mesh
///
Array BlendShapes;
///
/// Global translation for this mesh to be at it's local origin.
///
Vector3 OriginTranslation = Vector3::Zero;
///
/// Orientation for this mesh at it's local origin.
///
Quaternion OriginOrientation = Quaternion::Identity;
///
/// Meshes scaling.
///
Vector3 Scaling = Vector3::One;
public:
///
/// Determines whether this instance has any mesh data.
///
FORCE_INLINE bool HasData() const
{
return Indices.HasItems();
}
public:
///
/// Clear arrays
///
void Clear();
///
/// Ensure that buffers will have given space for data
///
/// Amount of vertices.
/// Amount of indices.
/// Failed if clear data otherwise will try to preserve the buffers contents.
/// True if use vertex colors buffer.
/// True if use vertex blend indices and weights buffer.
void EnsureCapacity(int32 vertices, int32 indices, bool preserveContents = false, bool withColors = true, bool withSkin = true);
///
/// Swaps the vertex and index buffers contents (without a data copy) with the other mesh.
///
/// The other mesh to swap data with.
void SwapBuffers(MeshData& other);
///
/// Clean data
///
void Release();
public:
///
/// Init from model vertices array
///
/// Array of vertices
/// Amount of vertices
void InitFromModelVertices(ModelVertex19* vertices, uint32 verticesCount);
///
/// Init from model vertices array
///
/// Array of vertices
/// Amount of vertices
void InitFromModelVertices(ModelVertex18* vertices, uint32 verticesCount);
///
/// Init from model vertices array
///
/// Array of vertices
/// Amount of vertices
void InitFromModelVertices(ModelVertex15* vertices, uint32 verticesCount);
///
/// Init from model vertices array
///
/// Array of data for vertex buffer 0
/// Array of data for vertex buffer 1
/// Amount of vertices
void InitFromModelVertices(VB0ElementType18* vb0, VB1ElementType18* vb1, uint32 verticesCount);
///
/// Init from model vertices array
///
/// Array of data for vertex buffer 0
/// Array of data for vertex buffer 1
/// Array of data for vertex buffer 2
/// Amount of vertices
void InitFromModelVertices(VB0ElementType18* vb0, VB1ElementType18* vb1, VB2ElementType18* vb2, uint32 verticesCount);
///
/// Init from model vertices array
///
/// Array of data for vertex buffer 0
/// Array of data for vertex buffer 1
/// Amount of vertices
void InitFromModelVertices(VB0ElementType15* vb0, VB1ElementType15* vb1, uint32 verticesCount);
///
/// Sets the index buffer data.
///
/// The data.
/// The indices count.
void SetIndexBuffer(void* data, uint32 indicesCount);
public:
///
/// Pack mesh data to the stream
///
/// Output stream
/// True if cannot save data, otherwise false
bool Pack2Model(WriteStream* stream) const;
///
/// Pack skinned mesh data to the stream
///
/// Output stream
/// True if cannot save data, otherwise false
bool Pack2SkinnedModel(WriteStream* stream) const;
///
/// Calculate bounding box for the mesh
///
/// Output box
void CalculateBox(BoundingBox& result) const;
///
/// Calculate bounding sphere for the mesh
///
/// Output sphere
void CalculateSphere(BoundingSphere& result) const;
public:
#if COMPILE_WITH_MODEL_TOOL
///
/// Generate lightmap uvs for the mesh entry
///
/// True if generating lightmap uvs failed, otherwise false
bool GenerateLightmapUVs();
///
/// Iterates over the vertex buffers to remove the duplicated vertices and generate the optimized index buffer.
///
void BuildIndexBuffer();
///
/// Generate lightmap uvs for the mesh entry
///
/// The target position to check.
/// The position comparision epsilon.
/// The output vertices indices array.
void FindPositions(const Float3& position, float epsilon, Array& result);
///
/// Generates the normal vectors for the mesh geometry.
///
/// Specifies the maximum angle (in degrees) that may be between two face normals at the same vertex position that their are smoothed together.
/// True if generating failed, otherwise false
bool GenerateNormals(float smoothingAngle = 175.0f);
///
/// Generates the tangent vectors for the mesh geometry. Requires normal vector and texture coords channel to be valid.
///
/// Specifies the maximum angle (in degrees) that may be between two vertex tangents that their tangents and bi-tangents are smoothed.
/// True if generating failed, otherwise false.
bool GenerateTangents(float smoothingAngle = 45.0f);
///
/// Reorders all triangles for improved vertex cache locality. It tries to arrange all triangles to fans and to render triangles which share vertices directly one after the other.
///
void ImproveCacheLocality();
///
/// Sums the area of all triangles in the mesh.
///
/// The area sum of all mesh triangles.
float CalculateTrianglesArea() const;
#endif
///
/// Transform a vertex buffer positions, normals, tangents and bitangents using the given matrix.
///
/// The matrix to use for the transformation.
void TransformBuffer(const Matrix& matrix);
///
/// Normalizes the blend weights. Requires to have vertices with positions and blend weights setup.
///
void NormalizeBlendWeights();
///
/// Merges this mesh data with the specified other mesh.
///
/// The other mesh to merge with.
void Merge(MeshData& other);
};
///
/// Model texture resource descriptor.
///
struct FLAXENGINE_API TextureEntry
{
enum class TypeHint
{
ColorRGB,
ColorRGBA,
Normals,
};
///
/// The absolute path to the file.
///
String FilePath;
///
/// The texture contents hint based on the usage/context.
///
TypeHint Type;
///
/// The texture asset identifier.
///
Guid AssetID;
};
///
/// Model material slot entry that describes model mesh appearance.
///
struct FLAXENGINE_API MaterialSlotEntry
{
///
/// The slot name.
///
String Name;
///
/// Gets or sets shadows casting mode by this visual element
///
ShadowsCastingMode ShadowsMode = ShadowsCastingMode::All;
///
/// The material asset identifier (material or material instance).
///
Guid AssetID;
struct
{
Color Color = Color::White;
int32 TextureIndex = -1;
bool HasAlphaMask = false;
} Diffuse;
struct
{
Color Color = Color::Transparent;
int32 TextureIndex = -1;
} Emissive;
struct
{
float Value = 1.0f;
int32 TextureIndex = -1;
} Opacity;
struct
{
int32 TextureIndex = -1;
} Normals;
bool TwoSided = false;
bool UsesProperties() const;
};
///
/// Data container for LOD metadata and sub meshes.
///
class FLAXENGINE_API ModelLodData
{
public:
///
/// The screen size to switch LODs. Bottom limit of the model screen size to render this LOD.
///
float ScreenSize = 1.0f;
///
/// The meshes array.
///
Array Meshes;
public:
///
/// Initializes a new instance of the class.
///
ModelLodData()
{
}
///
/// Finalizes an instance of the class.
///
~ModelLodData()
{
Meshes.ClearDelete();
}
///
/// Gets the bounding box combined for all meshes in this model LOD.
///
BoundingBox GetBox() const;
};
///
/// Data container for model metadata and LODs.
///
class FLAXENGINE_API ModelData
{
public:
///
/// The minimum screen size to draw model (the bottom limit).
///
float MinScreenSize = 0.0f;
///
/// The texture slots.
///
Array Textures;
///
/// The material slots.
///
Array Materials;
///
/// Array with all LODs. The first element is the top most LOD0 followed by the LOD1, LOD2, etc.
///
Array LODs;
///
/// The skeleton bones hierarchy.
///
SkeletonData Skeleton;
///
/// The node animations.
///
AnimationData Animation;
public:
///
/// Initializes a new instance of the class.
///
ModelData()
{
}
public:
///
/// Gets the valid level of details count.
///
/// The LOD count.
FORCE_INLINE int32 GetLODsCount() const
{
return LODs.Count();
}
///
/// Determines whether this instance has valid skeleton structure.
///
/// True if has skeleton, otherwise false.
FORCE_INLINE bool HasSkeleton() const
{
return Skeleton.Bones.HasItems();
}
public:
///
/// Automatically calculates the screen size for every model LOD for a proper transitions.
///
void CalculateLODsScreenSizes();
///
/// Transform a vertex buffer positions, normals, tangents and bitangents using the given matrix. Applies to all the LODs and meshes.
///
/// The matrix to use for the transformation.
void TransformBuffer(const Matrix& matrix);
public:
///
/// Pack mesh data to the header stream
///
/// Output stream
/// True if cannot save data, otherwise false
bool Pack2ModelHeader(WriteStream* stream) const;
///
/// Pack skinned mesh data to the header stream
///
/// Output stream
/// True if cannot save data, otherwise false
bool Pack2SkinnedModelHeader(WriteStream* stream) const;
///
/// Pack animation data to the header stream
///
/// Output stream
/// True if cannot save data, otherwise false
bool Pack2AnimationHeader(WriteStream* stream) const;
};