// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "MeshBase.h" #include "Types.h" #include "BlendShape.h" /// /// Represents part of the skinned model that is made of vertices and can be rendered using custom material, transformation and skeleton bones hierarchy. /// API_CLASS(NoSpawn) class FLAXENGINE_API SkinnedMesh : public MeshBase { DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(SkinnedMesh, MeshBase); protected: GPUBuffer* _vertexBuffer = nullptr; GPUBuffer* _indexBuffer = nullptr; mutable Array _cachedIndexBuffer; mutable Array _cachedVertexBuffer; mutable int32 _cachedIndexBufferCount; public: SkinnedMesh(const SkinnedMesh& other) : SkinnedMesh() { #if !BUILD_RELEASE CRASH; // Not used #endif } /// /// Finalizes an instance of the class. /// ~SkinnedMesh(); public: /// /// Gets the skinned model owning this mesh. /// FORCE_INLINE SkinnedModel* GetSkinnedModel() const { return (SkinnedModel*)_model; } /// /// Determines whether this mesh is initialized (has vertex and index buffers initialized). /// FORCE_INLINE bool IsInitialized() const { return _vertexBuffer != nullptr; } /// /// Blend shapes used by this mesh. /// Array BlendShapes; public: /// /// Initializes a new instance of the class. /// /// The model. /// The model LOD index. /// The mesh index. /// The material slot index to use. /// The bounding box. /// The bounding sphere. void Init(SkinnedModel* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere); /// /// Load mesh data and Initialize GPU buffers /// /// Amount of vertices in the vertex buffer /// Amount of triangles in the index buffer /// Vertex buffer data /// 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* ib, bool use16BitIndexBuffer); /// /// Unloads the mesh data (vertex buffers and cache). The opposite to Load. /// void Unload(); 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 vertex buffer data. /// The index buffer in clockwise order. /// True if failed, otherwise false. FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, int32* ib) { return UpdateMesh(vertexCount, triangleCount, vb, 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 vertex buffer data. /// The index buffer in clockwise order. /// True if failed, otherwise false. FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, uint32* ib) { return UpdateMesh(vertexCount, triangleCount, vb, 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 vertex buffer data. /// The index buffer, clockwise order. /// True if failed, otherwise false. FORCE_INLINE bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0SkinnedElementType* vb, uint16* ib) { return UpdateMesh(vertexCount, triangleCount, vb, 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 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, VB0SkinnedElementType* vb, void* ib, bool use16BitIndices); 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, Real& distance, Vector3& normal) const; /// /// Determines if there is an intersection between the mesh and a ray in given world /// /// The ray to test /// 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 bool Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal) const; public: /// /// 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 packed drawing info data. /// The LOD transition dither factor. void Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const; /// /// Draws the mesh. /// /// The rendering context batch. /// The packed drawing info data. /// The LOD transition dither factor. void Draw(const RenderContextBatch& renderContextBatch, 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(MArray* verticesObj, MArray* trianglesObj, MArray* blendIndicesObj, MArray* blendWeightsObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj); API_FUNCTION(NoProxy) bool UpdateMeshUShort(MArray* verticesObj, MArray* trianglesObj, MArray* blendIndicesObj, MArray* blendWeightsObj, MArray* normalsObj, MArray* tangentsObj, MArray* uvObj); API_FUNCTION(NoProxy) MArray* DownloadBuffer(bool forceGpu, MTypeObject* resultType, int32 typeI); #endif };