// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
#include "MeshBase.h"
#include "ModelInstanceEntry.h"
#include "Config.h"
#include "Types.h"
#include "Engine/Level/Types.h"
#if USE_PRECISE_MESH_INTERSECTS
#include "CollisionProxy.h"
#endif
struct GeometryDrawStateData;
class Lightmap;
class GPUBuffer;
///
/// Represents part of the model that is made of vertices and can be rendered using custom material and transformation.
///
API_CLASS(NoSpawn) class FLAXENGINE_API Mesh : public MeshBase
{
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(Mesh, MeshBase);
protected:
bool _hasLightmapUVs;
GPUBuffer* _vertexBuffers[3] = {};
GPUBuffer* _indexBuffer = nullptr;
#if USE_PRECISE_MESH_INTERSECTS
CollisionProxy _collisionProxy;
#endif
mutable Array _cachedVertexBuffer[3];
mutable Array _cachedIndexBuffer;
mutable int32 _cachedIndexBufferCount;
public:
Mesh(const Mesh& other)
: Mesh()
{
#if !BUILD_RELEASE
CRASH; // Not used
#endif
}
///
/// Finalizes an instance of the class.
///
~Mesh();
public:
///
/// Gets the model owning this mesh.
///
FORCE_INLINE Model* GetModel() const
{
return (Model*)_model;
}
///
/// Gets the index buffer.
///
FORCE_INLINE GPUBuffer* GetIndexBuffer() const
{
return _indexBuffer;
}
///
/// Gets the vertex buffer.
///
/// The index.
/// The buffer.
FORCE_INLINE GPUBuffer* GetVertexBuffer(int32 index) const
{
return _vertexBuffers[index];
}
///
/// Determines whether this mesh is initialized (has vertex and index buffers initialized).
///
FORCE_INLINE bool IsInitialized() const
{
return _vertexBuffers[0] != nullptr;
}
///
/// Determines whether this mesh has a vertex colors buffer.
///
API_PROPERTY() bool HasVertexColors() const;
///
/// Determines whether this mesh contains valid lightmap texture coordinates data.
///
API_PROPERTY() FORCE_INLINE bool HasLightmapUVs() const
{
return _hasLightmapUVs;
}
#if USE_PRECISE_MESH_INTERSECTS
///
/// Gets the collision proxy used by the mesh.
///
FORCE_INLINE const CollisionProxy& GetCollisionProxy() const
{
return _collisionProxy;
}
#endif
public:
///
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
///
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The first vertex buffer data.
/// The second vertex buffer data.
/// The third vertex buffer data.
/// The index buffer in clockwise order.
/// True if failed, otherwise false.
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint32* ib)
{
return UpdateMesh(vertexCount, triangleCount, vb0, vb1, vb2, ib, false);
}
///
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
///
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The first vertex buffer data.
/// The second vertex buffer data.
/// The third vertex buffer data.
/// The index buffer in clockwise order.
/// True if failed, otherwise false.
FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, uint16* ib)
{
return UpdateMesh(vertexCount, triangleCount, vb0, vb1, vb2, ib, true);
}
///
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
/// Can be used only for virtual assets (see and ).
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The first vertex buffer data.
/// The second vertex buffer data.
/// The third vertex buffer data.
/// The index buffer in clockwise order.
/// True if index buffer uses 16-bit index buffer, otherwise 32-bit.
/// True if failed, otherwise false.
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices);
///
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
/// Can be used only for virtual assets (see and ).
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The mesh vertices positions. Cannot be null.
/// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.
/// The normal vectors (per vertex).
/// The normal vectors (per vertex). Use null to compute them from normal vectors.
/// The texture coordinates (per vertex).
/// The vertex colors (per vertex).
/// True if failed, otherwise false.
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint16* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
///
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
/// Can be used only for virtual assets (see and ).
/// Mesh data will be cached and uploaded to the GPU with a delay.
///
/// The amount of vertices in the vertex buffer.
/// The amount of triangles in the index buffer.
/// The mesh vertices positions. Cannot be null.
/// The mesh index buffer (clockwise triangles). Uses 32-bit stride buffer. Cannot be null.
/// The normal vectors (per vertex).
/// The normal vectors (per vertex). Use null to compute them from normal vectors.
/// The texture coordinates (per vertex).
/// The vertex colors (per vertex).
/// True if failed, otherwise false.
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
public:
///
/// Updates the model mesh index buffer (used by the virtual models created with Init rather than Load).
///
/// The amount of triangles in the index buffer.
/// The index buffer.
/// True if failed, otherwise false.
FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, uint32* ib)
{
return UpdateTriangles(triangleCount, ib, false);
}
///
/// Updates the model mesh index buffer (used by the virtual models created with Init rather than Load).
///
/// The amount of triangles in the index buffer.
/// The index buffer.
/// True if failed, otherwise false.
FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, uint16* ib)
{
return UpdateTriangles(triangleCount, ib, true);
}
///
/// Updates the model mesh index buffer (used by the virtual models created with Init rather than Load).
///
/// The amount of triangles in the index buffer.
/// The index buffer.
/// True if index buffer uses 16-bit index buffer, otherwise 32-bit.
/// True if failed, otherwise false.
bool UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices);
public:
///
/// Initializes instance of the class.
///
/// The model.
/// The LOD index.
/// The mesh index.
/// The material slot index to use.
/// The bounding box.
/// The bounding sphere.
/// The lightmap UVs flag.
void Init(Model* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere, bool hasLightmapUVs);
///
/// Load mesh data and Initialize GPU buffers
///
/// Amount of vertices in the vertex buffer
/// Amount of triangles in the index buffer
/// Vertex buffer 0 data
/// Vertex buffer 1 data
/// Vertex buffer 2 data (may be null if not used)
/// Index buffer data
/// True if use 16 bit indices for the index buffer (true: uint16, false: uint32).
/// True if cannot load data, otherwise false.
bool Load(uint32 vertices, uint32 triangles, void* vb0, void* vb1, void* vb2, void* ib, bool use16BitIndexBuffer);
///
/// Unloads the mesh data (vertex buffers and cache). The opposite to Load.
///
void Unload();
public:
///
/// Determines if there is an intersection between the mesh and a ray in given world
///
/// The ray to test
/// World to transform box
/// When the method completes and returns true, contains the distance of the intersection (if any valid).
/// When the method completes, contains the intersection surface normal vector (if any valid).
/// True whether the two objects intersected
bool Intersects(const Ray& ray, const Matrix& world, float& distance, Vector3& normal) const;
///
/// Retrieves the eight corners of the bounding box.
///
/// An array of points representing the eight corners of the bounding box.
FORCE_INLINE void GetCorners(Vector3 corners[8]) const
{
_box.GetCorners(corners);
}
public:
///
/// Gets the draw call geometry for this mesh. Sets the index and vertex buffers.
///
/// The draw call.
void GetDrawCallGeometry(DrawCall& drawCall) const;
///
/// Model instance drawing packed data.
///
struct DrawInfo
{
///
/// The instance buffer to use during model rendering.
///
ModelInstanceEntries* Buffer;
///
/// The world transformation of the model.
///
Matrix* World;
///
/// The instance drawing state data container. Used for LOD transition handling and previous world transformation matrix updating.
///
GeometryDrawStateData* DrawState;
///
/// The lightmap.
///
const Lightmap* Lightmap;
///
/// The lightmap UVs.
///
const Rectangle* LightmapUVs;
///
/// The model instance vertex colors buffers (per-lod all meshes packed in a single allocation, array length equal to model lods count).
///
GPUBuffer** VertexColors;
///
/// The object static flags.
///
StaticFlags Flags;
///
/// The object draw modes.
///
DrawPass DrawModes;
///
/// The bounds of the model (used to select a proper LOD during rendering).
///
BoundingSphere Bounds;
///
/// The per-instance random value.
///
float PerInstanceRandom;
///
/// The LOD bias value.
///
char LODBias;
///
/// The forced LOD to use. Value -1 disables this feature.
///
char ForcedLOD;
};
///
/// Draws the mesh. Binds vertex and index buffers and invokes the draw call.
///
/// The GPU context.
void Render(GPUContext* context) const;
///
/// Draws the mesh.
///
/// The rendering context.
/// The material to use for rendering.
/// The world transformation of the model.
/// The object static flags.
/// True if rendered geometry can receive decals, otherwise false.
/// The draw passes to use for rendering this object.
/// The random per-instance value (normalized to range 0-1).
API_FUNCTION() void Draw(API_PARAM(Ref) const RenderContext& renderContext, MaterialBase* material, API_PARAM(Ref) const Matrix& world, StaticFlags flags = StaticFlags::None, bool receiveDecals = true, DrawPass drawModes = DrawPass::Default, float perInstanceRandom = 0.0f) const;
///
/// Draws the mesh.
///
/// The rendering context.
/// The packed drawing info data.
/// The LOD transition dither factor.
void Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const;
public:
// [MeshBase]
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const override;
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const override;
private:
// Internal bindings
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
#if !COMPILE_WITHOUT_CSHARP
API_FUNCTION(NoProxy) bool UpdateMeshUInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
API_FUNCTION(NoProxy) bool UpdateMeshUShort(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
#endif
};