// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Math/BoundingBox.h" #include "Engine/Core/Math/BoundingSphere.h" #include "Engine/Core/Types/DataContainer.h" #include "Engine/Core/Collections/Array.h" #include "Engine/Graphics/Enums.h" #include "Engine/Graphics/Models/Types.h" #include "Engine/Level/Types.h" #include "Engine/Scripting/ScriptingObject.h" #include "Config.h" #if USE_PRECISE_MESH_INTERSECTS #include "CollisionProxy.h" #endif struct GeometryDrawStateData; struct RenderContext; struct RenderContextBatch; class Task; class ModelBase; class Lightmap; class GPUBuffer; class SkinnedMeshDrawData; class BlendShapesInstance; /// /// Base class for mesh objects. /// API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API MeshBase : public ScriptingObject { DECLARE_SCRIPTING_TYPE_MINIMAL(MeshBase); protected: ModelBase* _model; BoundingBox _box; BoundingSphere _sphere; int32 _index; int32 _lodIndex; uint32 _vertices; uint32 _triangles; int32 _materialSlotIndex; bool _use16BitIndexBuffer; GPUBuffer* _vertexBuffers[3] = {}; GPUBuffer* _indexBuffer = nullptr; mutable Array _cachedVertexBuffers[3]; mutable Array _cachedIndexBuffer; mutable int32 _cachedIndexBufferCount; #if USE_PRECISE_MESH_INTERSECTS CollisionProxy _collisionProxy; #endif explicit MeshBase(const SpawnParams& params) : ScriptingObject(params) { } public: ~MeshBase(); /// /// Gets the model owning this mesh. /// API_PROPERTY() FORCE_INLINE ModelBase* GetModelBase() const { return _model; } /// /// Gets the mesh parent LOD index. /// API_PROPERTY() FORCE_INLINE int32 GetLODIndex() const { return _lodIndex; } /// /// Gets the mesh index. /// API_PROPERTY() FORCE_INLINE int32 GetIndex() const { return _index; } /// /// Gets the triangle count. /// API_PROPERTY() FORCE_INLINE int32 GetTriangleCount() const { return _triangles; } /// /// Gets the vertex count. /// API_PROPERTY() FORCE_INLINE int32 GetVertexCount() const { return _vertices; } /// /// Gets the box. /// API_PROPERTY() FORCE_INLINE const BoundingBox& GetBox() const { return _box; } /// /// Gets the sphere. /// API_PROPERTY() FORCE_INLINE const BoundingSphere& GetSphere() const { return _sphere; } /// /// Determines whether this mesh is using 16 bit index buffer, otherwise it's 32 bit. /// API_PROPERTY() FORCE_INLINE bool Use16BitIndexBuffer() const { return _use16BitIndexBuffer; } #if USE_PRECISE_MESH_INTERSECTS /// /// Gets the collision proxy used by the mesh. /// FORCE_INLINE const CollisionProxy& GetCollisionProxy() const { return _collisionProxy; } #endif /// /// 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; /// /// Gets the index of the material slot to use during this mesh rendering. /// API_PROPERTY() FORCE_INLINE int32 GetMaterialSlotIndex() const { return _materialSlotIndex; } /// /// Sets the index of the material slot to use during this mesh rendering. /// API_PROPERTY() void SetMaterialSlotIndex(int32 value); /// /// Sets the mesh bounds. /// /// The bounding box. void SetBounds(const BoundingBox& box); /// /// Gets the index buffer. /// FORCE_INLINE GPUBuffer* GetIndexBuffer() const { return _indexBuffer; } /// /// Gets the vertex buffer. /// /// The bind slot index. /// The buffer or null if not used. FORCE_INLINE GPUBuffer* GetVertexBuffer(int32 index) const { return _vertexBuffers[index]; } public: /// /// Unloads the mesh data (vertex buffers and cache). The opposite to Load. /// void Unload(); public: /// /// Updates the model mesh index buffer. /// /// The amount of triangles in the index buffer. /// The index buffer. /// True if failed, otherwise false. FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, const uint32* ib) { return UpdateTriangles(triangleCount, ib, false); } /// /// Updates the model mesh index buffer. /// /// The amount of triangles in the index buffer. /// The index buffer. /// True if failed, otherwise false. FORCE_INLINE bool UpdateTriangles(uint32 triangleCount, const uint16* ib) { return UpdateTriangles(triangleCount, ib, true); } /// /// Updates the model mesh index buffer. /// /// 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, const void* ib, bool use16BitIndices); public: /// /// Determines if there is an intersection between the mesh and a ray in given world. /// /// The ray to test. /// The mesh instance transformation. /// 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, otherwise false. bool Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal) const; /// /// Determines if there is an intersection between the mesh and a ray in given world /// /// The ray to test /// The mesh instance transformation. /// 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, otherwise false. bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const; public: /// /// Extracts mesh buffer data from a GPU. Cannot be called from the main thread. /// /// Buffer type /// The result data /// True if failed, otherwise false bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const; /// /// Extracts mesh buffer data from GPU in the async task. /// /// Buffer type /// The result data /// Created async task used to gather the buffer data. Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const; /// /// Extract mesh buffer data from CPU. Cached internally. /// /// Buffer type /// The result data /// The amount of items inside the result buffer. /// True if failed, otherwise false virtual bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const = 0; public: /// /// 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 instance deformation utility. /// MeshDeformation* Deformation; union { struct { /// /// The skinning. /// SkinnedMeshDrawData* Skinning; }; struct { /// /// 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; /// /// The object sorting key. /// int8 SortOrder; #if USE_EDITOR float LightmapScale = -1.0f; #endif }; /// /// Gets the draw call geometry for this mesh. Sets the index and vertex buffers. /// /// The draw call. void GetDrawCallGeometry(struct DrawCall& drawCall) const; /// /// Draws the mesh. Binds vertex and index buffers and invokes the draw call. /// /// The GPU context. void Render(GPUContext* context) const; private: // Internal bindings API_FUNCTION(NoProxy) ScriptingObject* GetParentModel() const; #if !COMPILE_WITHOUT_CSHARP API_FUNCTION(NoProxy) bool UpdateTrianglesUInt(int32 triangleCount, const MArray* trianglesObj); API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, const MArray* trianglesObj); #endif };