// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Core/Math/BoundingBox.h" #include "Engine/Core/Math/BoundingSphere.h" #include "Engine/Scripting/ScriptingObject.h" #include "Engine/Renderer/RenderList.h" #include "Engine/Graphics/RenderTask.h" #include "ModelInstanceEntry.h" #include "Config.h" #include "Types.h" #if USE_PRECISE_MESH_INTERSECTS #include "CollisionProxy.h" #endif 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 PersistentScriptingObject { DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(Mesh, PersistentScriptingObject); protected: Model* _model; int32 _index; int32 _lodIndex; int32 _materialSlotIndex; bool _use16BitIndexBuffer; bool _hasLightmapUVs; BoundingBox _box; BoundingSphere _sphere; uint32 _vertices; uint32 _triangles; GPUBuffer* _vertexBuffers[3]; GPUBuffer* _indexBuffer; #if USE_PRECISE_MESH_INTERSECTS CollisionProxy _collisionProxy; #endif 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; } /// /// Gets the mesh parent LOD index. /// FORCE_INLINE int32 GetLODIndex() const { return _lodIndex; } /// /// Gets the mesh index. /// FORCE_INLINE int32 GetIndex() const { return _index; } /// /// 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); /// /// 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 index buffer. /// /// The 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). /// /// True if this instance is initialized, otherwise false. FORCE_INLINE bool IsInitialized() const { return _vertexBuffers[0] != nullptr; } /// /// Determines whether this mesh is using 16 bit index buffer, otherwise it's 32 bit. /// /// True if this mesh is using 16 bit index buffer, otherwise 32 bit index buffer. API_PROPERTY() FORCE_INLINE bool Use16BitIndexBuffer() const { return _use16BitIndexBuffer; } /// /// Determines whether this mesh has a vertex colors buffer. /// /// True if this mesh has a vertex colors buffers. API_PROPERTY() FORCE_INLINE bool HasVertexColors() const { return _vertexBuffers[2] != nullptr && _vertexBuffers[2]->IsAllocated(); } /// /// Determines whether this mesh contains valid lightmap texture coordinates data. /// /// True if this mesh has a vertex colors buffers. API_PROPERTY() FORCE_INLINE bool HasLightmapUVs() const { return _hasLightmapUVs; } /// /// Sets the mesh bounds. /// /// The bounding box. void SetBounds(const BoundingBox& box) { _box = box; BoundingSphere::FromBox(box, _sphere); } /// /// Gets the box. /// /// The bounding box. API_PROPERTY() FORCE_INLINE const BoundingBox& GetBox() const { return _box; } /// /// Gets the sphere. /// /// The bounding sphere. API_PROPERTY() FORCE_INLINE const BoundingSphere& GetSphere() const { return _sphere; } #if USE_PRECISE_MESH_INTERSECTS /// /// Gets the collision proxy used by the mesh. /// /// The collisions proxy container object reference. 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. /// True if failed, otherwise false. FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, int32* 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. /// 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). /// /// 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. /// 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); 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, int32* 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); /// /// 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. 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) 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: /// /// Extract mesh buffer data (cannot be called from the main thread!). /// /// Buffer type /// The result data /// True if failed, otherwise false bool ExtractData(MeshBufferType type, BytesContainer& result) const; /// /// Extracts mesh buffer data in the async task. /// /// Buffer type /// The result data /// Created async task used to gather the buffer data. Task* ExtractDataAsync(MeshBufferType type, BytesContainer& result) const; private: // Internal bindings API_FUNCTION(NoProxy) ScriptingObject* GetParentModel(); API_FUNCTION(NoProxy) bool UpdateMeshInt(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 UpdateTrianglesInt(int32 triangleCount, MonoArray* trianglesObj); API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj); API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI); };