Refactor models and meshes to share more code in a base class
This commit is contained in:
@@ -31,12 +31,12 @@ public:
|
||||
}
|
||||
|
||||
template<typename IndexType>
|
||||
void Init(uint32 vertices, uint32 triangles, Float3* positions, IndexType* indices)
|
||||
void Init(uint32 vertices, uint32 triangles, const Float3* positions, const IndexType* indices)
|
||||
{
|
||||
Triangles.Clear();
|
||||
Triangles.EnsureCapacity(triangles, false);
|
||||
|
||||
IndexType* it = indices;
|
||||
const IndexType* it = indices;
|
||||
for (uint32 i = 0; i < triangles; i++)
|
||||
{
|
||||
auto i0 = *(it++);
|
||||
|
||||
@@ -136,26 +136,17 @@ namespace
|
||||
|
||||
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const VB0ElementType* vb0, const VB1ElementType* vb1, const VB2ElementType* vb2, const void* ib, bool use16BitIndices)
|
||||
{
|
||||
auto model = (Model*)_model;
|
||||
|
||||
Unload();
|
||||
Release();
|
||||
|
||||
// Setup GPU resources
|
||||
model->LODs[_lodIndex]._verticesCount -= _vertices;
|
||||
const bool failed = Load(vertexCount, triangleCount, vb0, vb1, vb2, ib, use16BitIndices);
|
||||
if (!failed)
|
||||
{
|
||||
model->LODs[_lodIndex]._verticesCount += _vertices;
|
||||
|
||||
// Calculate mesh bounds
|
||||
BoundingBox bounds;
|
||||
BoundingBox::FromPoints((const Float3*)vb0, vertexCount, bounds);
|
||||
SetBounds(bounds);
|
||||
|
||||
// Send event (actors using this model can update bounds, etc.)
|
||||
model->onLoaded();
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
@@ -169,90 +160,19 @@ bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const Float3* ve
|
||||
return ::UpdateMesh<uint32>(this, vertexCount, triangleCount, vertices, triangles, normals, tangents, uvs, colors);
|
||||
}
|
||||
|
||||
void Mesh::Init(Model* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere, bool hasLightmapUVs)
|
||||
{
|
||||
_model = model;
|
||||
_lodIndex = lodIndex;
|
||||
_index = index;
|
||||
_materialSlotIndex = materialSlotIndex;
|
||||
_use16BitIndexBuffer = false;
|
||||
_hasLightmapUVs = hasLightmapUVs;
|
||||
_box = box;
|
||||
_sphere = sphere;
|
||||
_vertices = 0;
|
||||
_triangles = 0;
|
||||
_vertexBuffers[0] = nullptr;
|
||||
_vertexBuffers[1] = nullptr;
|
||||
_vertexBuffers[2] = nullptr;
|
||||
_indexBuffer = nullptr;
|
||||
}
|
||||
|
||||
bool Mesh::Load(uint32 vertices, uint32 triangles, const void* vb0, const void* vb1, const void* vb2, const void* ib, bool use16BitIndexBuffer)
|
||||
{
|
||||
// Cache data
|
||||
uint32 indicesCount = triangles * 3;
|
||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
|
||||
GPUBuffer* vertexBuffer0 = nullptr;
|
||||
GPUBuffer* vertexBuffer1 = nullptr;
|
||||
GPUBuffer* vertexBuffer2 = nullptr;
|
||||
GPUBuffer* indexBuffer = nullptr;
|
||||
|
||||
// Create GPU buffers
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
#define MESH_BUFFER_NAME(postfix) GetModel()->GetPath() + TEXT(postfix)
|
||||
#else
|
||||
#define MESH_BUFFER_NAME(postfix) String::Empty
|
||||
#endif
|
||||
vertexBuffer0 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB0"));
|
||||
if (vertexBuffer0->Init(GPUBufferDescription::Vertex(VB0ElementType::GetLayout(), sizeof(VB0ElementType), vertices, vb0)))
|
||||
goto ERROR_LOAD_END;
|
||||
vertexBuffer1 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB1"));
|
||||
if (vertexBuffer1->Init(GPUBufferDescription::Vertex(VB1ElementType::GetLayout(), sizeof(VB1ElementType), vertices, vb1)))
|
||||
goto ERROR_LOAD_END;
|
||||
Array<const void*, FixedAllocation<3>> vbData;
|
||||
vbData.Add(vb0);
|
||||
if (vb1)
|
||||
vbData.Add(vb1);
|
||||
if (vb2)
|
||||
{
|
||||
vertexBuffer2 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB2"));
|
||||
if (vertexBuffer2->Init(GPUBufferDescription::Vertex(VB2ElementType::GetLayout(), sizeof(VB2ElementType), vertices, vb2)))
|
||||
goto ERROR_LOAD_END;
|
||||
}
|
||||
indexBuffer = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".IB"));
|
||||
if (indexBuffer->Init(GPUBufferDescription::Index(ibStride, indicesCount, ib)))
|
||||
goto ERROR_LOAD_END;
|
||||
|
||||
// Init collision proxy
|
||||
#if USE_PRECISE_MESH_INTERSECTS
|
||||
if (!_collisionProxy.HasData())
|
||||
{
|
||||
if (use16BitIndexBuffer)
|
||||
_collisionProxy.Init<uint16>(vertices, triangles, (Float3*)vb0, (uint16*)ib);
|
||||
else
|
||||
_collisionProxy.Init<uint32>(vertices, triangles, (Float3*)vb0, (uint32*)ib);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize
|
||||
_vertexBuffers[0] = vertexBuffer0;
|
||||
_vertexBuffers[1] = vertexBuffer1;
|
||||
_vertexBuffers[2] = vertexBuffer2;
|
||||
_indexBuffer = indexBuffer;
|
||||
_triangles = triangles;
|
||||
_vertices = vertices;
|
||||
_use16BitIndexBuffer = use16BitIndexBuffer;
|
||||
_cachedVertexBuffers[0].Clear();
|
||||
_cachedVertexBuffers[1].Clear();
|
||||
_cachedVertexBuffers[2].Clear();
|
||||
|
||||
return false;
|
||||
|
||||
#undef MESH_BUFFER_NAME
|
||||
ERROR_LOAD_END:
|
||||
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexBuffer0);
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexBuffer1);
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexBuffer2);
|
||||
SAFE_DELETE_GPU_RESOURCE(indexBuffer);
|
||||
return true;
|
||||
vbData.Add(vb2);
|
||||
Array<GPUVertexLayout*, FixedAllocation<3>> vbLayout;
|
||||
vbLayout.Add(VB0ElementType::GetLayout());
|
||||
vbLayout.Add(VB1ElementType::GetLayout());
|
||||
vbLayout.Add(VB2ElementType::GetLayout());
|
||||
return Init(vertices, triangles, vbData, ib, use16BitIndexBuffer, vbLayout);
|
||||
}
|
||||
|
||||
void Mesh::Draw(const RenderContext& renderContext, MaterialBase* material, const Matrix& world, StaticFlags flags, bool receiveDecals, DrawPass drawModes, float perInstanceRandom, int8 sortOrder) const
|
||||
@@ -424,6 +344,26 @@ void Mesh::Draw(const RenderContextBatch& renderContextBatch, const DrawInfo& in
|
||||
renderContextBatch.GetMainContext().List->AddDrawCall(renderContextBatch, drawModes, info.Flags, shadowsMode, info.Bounds, drawCall, entry.ReceiveDecals, info.SortOrder);
|
||||
}
|
||||
|
||||
bool Mesh::Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<3>>& vbLayout)
|
||||
{
|
||||
if (MeshBase::Init(vertices, triangles, vbData, ibData, use16BitIndexBuffer, vbLayout))
|
||||
return true;
|
||||
|
||||
auto model = (Model*)_model;
|
||||
if (model)
|
||||
model->LODs[_lodIndex]._verticesCount += _vertices;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mesh::Release()
|
||||
{
|
||||
auto model = (Model*)_model;
|
||||
if (model)
|
||||
model->LODs[_lodIndex]._verticesCount -= _vertices;
|
||||
|
||||
MeshBase::Release();
|
||||
}
|
||||
|
||||
bool Mesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const
|
||||
{
|
||||
if (_cachedVertexBuffers[0].IsEmpty())
|
||||
|
||||
@@ -16,9 +16,6 @@ API_CLASS(NoSpawn) class FLAXENGINE_API Mesh : public MeshBase
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(Mesh, MeshBase);
|
||||
|
||||
protected:
|
||||
bool _hasLightmapUVs;
|
||||
|
||||
public:
|
||||
Mesh(const Mesh& other)
|
||||
: Mesh()
|
||||
@@ -40,11 +37,16 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this mesh contains valid lightmap texture coordinates data.
|
||||
/// </summary>
|
||||
API_PROPERTY() FORCE_INLINE bool HasLightmapUVs() const
|
||||
API_PROPERTY() bool HasLightmapUVs() const
|
||||
{
|
||||
return _hasLightmapUVs;
|
||||
return LightmapUVsIndex != -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lightmap texture coordinates channel index.
|
||||
/// </summary>
|
||||
API_FIELD() int32 LightmapUVsIndex = -1;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
||||
@@ -124,20 +126,9 @@ public:
|
||||
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, const Float3* vertices, const uint32* triangles, const Float3* normals = nullptr, const Float3* tangents = nullptr, const Float2* uvs = nullptr, const Color32* colors = nullptr);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes instance of the <see cref="Mesh"/> class.
|
||||
/// </summary>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <param name="lodIndex">The LOD index.</param>
|
||||
/// <param name="index">The mesh index.</param>
|
||||
/// <param name="materialSlotIndex">The material slot index to use.</param>
|
||||
/// <param name="box">The bounding box.</param>
|
||||
/// <param name="sphere">The bounding sphere.</param>
|
||||
/// <param name="hasLightmapUVs">The lightmap UVs flag.</param>
|
||||
void Init(Model* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere, bool hasLightmapUVs);
|
||||
|
||||
/// <summary>
|
||||
/// Load mesh data and Initialize GPU buffers
|
||||
/// [Deprecated in v1.10]
|
||||
/// </summary>
|
||||
/// <param name="vertices">Amount of vertices in the vertex buffer</param>
|
||||
/// <param name="triangles">Amount of triangles in the index buffer</param>
|
||||
@@ -147,7 +138,7 @@ public:
|
||||
/// <param name="ib">Index buffer data</param>
|
||||
/// <param name="use16BitIndexBuffer">True if use 16 bit indices for the index buffer (true: uint16, false: uint32).</param>
|
||||
/// <returns>True if cannot load data, otherwise false.</returns>
|
||||
bool Load(uint32 vertices, uint32 triangles, const void* vb0, const void* vb1, const void* vb2, const void* ib, bool use16BitIndexBuffer);
|
||||
DEPRECATED("Use Init intead.") bool Load(uint32 vertices, uint32 triangles, const void* vb0, const void* vb1, const void* vb2, const void* ib, bool use16BitIndexBuffer);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -181,6 +172,8 @@ public:
|
||||
|
||||
public:
|
||||
// [MeshBase]
|
||||
bool Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<3>>& vbLayout) override;
|
||||
void Release() override;
|
||||
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -48,7 +48,6 @@ void MeshBase::SetMaterialSlotIndex(int32 value)
|
||||
LOG(Warning, "Cannot set mesh material slot to {0} while model has {1} slots.", value, _model->MaterialSlots.Count());
|
||||
return;
|
||||
}
|
||||
|
||||
_materialSlotIndex = value;
|
||||
}
|
||||
|
||||
@@ -56,9 +55,94 @@ void MeshBase::SetBounds(const BoundingBox& box)
|
||||
{
|
||||
_box = box;
|
||||
BoundingSphere::FromBox(box, _sphere);
|
||||
_hasBounds = true;
|
||||
}
|
||||
|
||||
void MeshBase::Unload()
|
||||
void MeshBase::SetBounds(const BoundingBox& box, const BoundingSphere& sphere)
|
||||
{
|
||||
_box = box;
|
||||
_sphere = sphere;
|
||||
_hasBounds = true;
|
||||
if (_model && _model->IsLoaded())
|
||||
{
|
||||
// Send event (actors using this model can update bounds, etc.)
|
||||
_model->onLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
bool MeshBase::Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<3>>& vbLayout)
|
||||
{
|
||||
CHECK_RETURN(vbData.HasItems() && vertices, true);
|
||||
CHECK_RETURN(ibData, true);
|
||||
CHECK_RETURN(vbLayout.Count() >= vbData.Count(), true);
|
||||
ASSERT(_model);
|
||||
GPUBuffer* vertexBuffer0 = nullptr;
|
||||
GPUBuffer* vertexBuffer1 = nullptr;
|
||||
GPUBuffer* vertexBuffer2 = nullptr;
|
||||
GPUBuffer* indexBuffer = nullptr;
|
||||
|
||||
// Create GPU buffers
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
const String& modelPath = _model->GetPath();
|
||||
#define MESH_BUFFER_NAME(postfix) modelPath + TEXT(postfix)
|
||||
#else
|
||||
#define MESH_BUFFER_NAME(postfix) String::Empty
|
||||
#endif
|
||||
vertexBuffer0 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB0"));
|
||||
if (vertexBuffer0->Init(GPUBufferDescription::Vertex(vbLayout[0], vertices, vbData[0])))
|
||||
goto ERROR_LOAD_END;
|
||||
if (vbData.Count() >= 2 && vbData[1])
|
||||
{
|
||||
vertexBuffer1 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB1"));
|
||||
if (vertexBuffer1->Init(GPUBufferDescription::Vertex(vbLayout[1], vertices, vbData[1])))
|
||||
goto ERROR_LOAD_END;
|
||||
}
|
||||
if (vbData.Count() >= 3 && vbData[2])
|
||||
{
|
||||
vertexBuffer2 = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".VB2"));
|
||||
if (vertexBuffer2->Init(GPUBufferDescription::Vertex(vbLayout[2], vertices, vbData[2])))
|
||||
goto ERROR_LOAD_END;
|
||||
}
|
||||
indexBuffer = GPUDevice::Instance->CreateBuffer(MESH_BUFFER_NAME(".IB"));
|
||||
if (indexBuffer->Init(GPUBufferDescription::Index(use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32), triangles * 3, ibData)))
|
||||
goto ERROR_LOAD_END;
|
||||
|
||||
// Init collision proxy
|
||||
#if USE_PRECISE_MESH_INTERSECTS
|
||||
if (!_collisionProxy.HasData())
|
||||
{
|
||||
if (use16BitIndexBuffer)
|
||||
_collisionProxy.Init<uint16>(vertices, triangles, (const Float3*)vbData[0], (const uint16*)ibData);
|
||||
else
|
||||
_collisionProxy.Init<uint32>(vertices, triangles, (const Float3*)vbData[0], (const uint32*)ibData);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize
|
||||
_vertexBuffers[0] = vertexBuffer0;
|
||||
_vertexBuffers[1] = vertexBuffer1;
|
||||
_vertexBuffers[2] = vertexBuffer2;
|
||||
_indexBuffer = indexBuffer;
|
||||
_triangles = triangles;
|
||||
_vertices = vertices;
|
||||
_use16BitIndexBuffer = use16BitIndexBuffer;
|
||||
_cachedVertexBuffers[0].Clear();
|
||||
_cachedVertexBuffers[1].Clear();
|
||||
_cachedVertexBuffers[2].Clear();
|
||||
|
||||
return false;
|
||||
|
||||
#undef MESH_BUFFER_NAME
|
||||
ERROR_LOAD_END:
|
||||
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexBuffer0);
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexBuffer1);
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexBuffer2);
|
||||
SAFE_DELETE_GPU_RESOURCE(indexBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MeshBase::Release()
|
||||
{
|
||||
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[0]);
|
||||
SAFE_DELETE_GPU_RESOURCE(_vertexBuffers[1]);
|
||||
|
||||
@@ -31,30 +31,40 @@ class BlendShapesInstance;
|
||||
API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API MeshBase : public ScriptingObject
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(MeshBase);
|
||||
friend class Model;
|
||||
friend class SkinnedModel;
|
||||
|
||||
protected:
|
||||
ModelBase* _model;
|
||||
BoundingBox _box;
|
||||
BoundingSphere _sphere;
|
||||
ModelBase* _model = nullptr;
|
||||
BoundingBox _box = BoundingBox::Zero;
|
||||
BoundingSphere _sphere = BoundingSphere::Empty;
|
||||
|
||||
int32 _index;
|
||||
int32 _lodIndex;
|
||||
uint32 _vertices;
|
||||
uint32 _triangles;
|
||||
int32 _materialSlotIndex;
|
||||
bool _use16BitIndexBuffer;
|
||||
int32 _index = 0;
|
||||
int32 _lodIndex = 0;
|
||||
uint32 _vertices = 0;
|
||||
uint32 _triangles = 0;
|
||||
int32 _materialSlotIndex = 0;
|
||||
bool _use16BitIndexBuffer = false;
|
||||
bool _hasBounds = false;
|
||||
|
||||
GPUBuffer* _vertexBuffers[3] = {};
|
||||
GPUBuffer* _indexBuffer = nullptr;
|
||||
|
||||
mutable Array<byte> _cachedVertexBuffers[3];
|
||||
mutable Array<byte> _cachedIndexBuffer;
|
||||
mutable int32 _cachedIndexBufferCount;
|
||||
mutable int32 _cachedIndexBufferCount = 0;
|
||||
|
||||
#if USE_PRECISE_MESH_INTERSECTS
|
||||
CollisionProxy _collisionProxy;
|
||||
#endif
|
||||
|
||||
void Link(ModelBase* model, int32 lodIndex, int32 index)
|
||||
{
|
||||
_model = model;
|
||||
_lodIndex = lodIndex;
|
||||
_index = index;
|
||||
}
|
||||
|
||||
explicit MeshBase(const SpawnParams& params)
|
||||
: ScriptingObject(params)
|
||||
{
|
||||
@@ -169,6 +179,13 @@ public:
|
||||
/// <param name="box">The bounding box.</param>
|
||||
void SetBounds(const BoundingBox& box);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mesh bounds.
|
||||
/// </summary>
|
||||
/// <param name="box">The bounding box.</param>
|
||||
/// <param name="sphere">The bounding sphere.</param>
|
||||
void SetBounds(const BoundingBox& box, const BoundingSphere& sphere);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the index buffer.
|
||||
/// </summary>
|
||||
@@ -189,9 +206,30 @@ public:
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Unloads the mesh data (vertex buffers and cache). The opposite to Load.
|
||||
/// Initializes the mesh buffers.
|
||||
/// </summary>
|
||||
void Unload();
|
||||
/// <param name="vertices">Amount of vertices in the vertex buffer.</param>
|
||||
/// <param name="triangles">Amount of triangles in the index buffer.</param>
|
||||
/// <param name="vbData">Array with pointers to vertex buffers initial data (layout defined by <paramref name="vertexLayout"/>).</param>
|
||||
/// <param name="ibData">Pointer to index buffer data. Data is uint16 or uint32 depending on <paramref name="use16BitIndexBuffer"/> value.</param>
|
||||
/// <param name="use16BitIndexBuffer">True to use 16-bit indices for the index buffer (true: uint16, false: uint32).</param>
|
||||
/// <param name="vbLayout">Layout descriptors for the vertex buffers attributes (one for each vertex buffer).</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
virtual bool Init(uint32 vertices, uint32 triangles, const Array<const void*, FixedAllocation<3>>& vbData, const void* ibData, bool use16BitIndexBuffer, const Array<GPUVertexLayout*, FixedAllocation<3>>& vbLayout);
|
||||
|
||||
/// <summary>
|
||||
/// Releases the mesh data (GPU buffers and local cache).
|
||||
/// </summary>
|
||||
virtual void Release();
|
||||
|
||||
/// <summary>
|
||||
/// Unloads the mesh data (vertex buffers and cache). The opposite to Load.
|
||||
/// [Deprecated in v1.10]
|
||||
/// </summary>
|
||||
DEPRECATED("Use Release instead.") void Unload()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ModelLOD.h"
|
||||
#include "MeshDeformation.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
|
||||
bool ModelLOD::Load(MemoryReadStream& stream)
|
||||
{
|
||||
// Load LOD for each mesh
|
||||
_verticesCount = 0;
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
// #MODEL_DATA_FORMAT_USAGE
|
||||
uint32 vertices;
|
||||
stream.ReadUint32(&vertices);
|
||||
_verticesCount += vertices;
|
||||
uint32 triangles;
|
||||
stream.ReadUint32(&triangles);
|
||||
uint32 indicesCount = triangles * 3;
|
||||
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
if (vertices == 0 || triangles == 0)
|
||||
return true;
|
||||
auto vb0 = stream.Move<VB0ElementType>(vertices);
|
||||
auto vb1 = stream.Move<VB1ElementType>(vertices);
|
||||
bool hasColors = stream.ReadBool();
|
||||
VB2ElementType18* vb2 = nullptr;
|
||||
if (hasColors)
|
||||
{
|
||||
vb2 = stream.Move<VB2ElementType18>(vertices);
|
||||
}
|
||||
auto ib = stream.Move<byte>(indicesCount * ibStride);
|
||||
|
||||
// Setup GPU resources
|
||||
if (Meshes[i].Load(vertices, triangles, vb0, vb1, vb2, ib, use16BitIndexBuffer))
|
||||
{
|
||||
LOG(Warning, "Cannot initialize mesh {0}. Vertices: {1}, triangles: {2}", i, vertices, triangles);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ModelLOD::Unload()
|
||||
{
|
||||
// Unload LOD for each mesh
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes[i].Unload();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelLOD::Dispose()
|
||||
{
|
||||
_model = nullptr;
|
||||
ScreenSize = 0.0f;
|
||||
Meshes.Resize(0);
|
||||
}
|
||||
|
||||
bool ModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, Mesh** mesh)
|
||||
{
|
||||
bool result = false;
|
||||
Real closest = MAX_Real;
|
||||
Vector3 closestNormal = Vector3::Up;
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Real dst;
|
||||
Vector3 nrm;
|
||||
if (Meshes[i].Intersects(ray, world, dst, nrm) && dst < closest)
|
||||
{
|
||||
result = true;
|
||||
*mesh = &Meshes[i];
|
||||
closest = dst;
|
||||
closestNormal = nrm;
|
||||
}
|
||||
}
|
||||
distance = closest;
|
||||
normal = closestNormal;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ModelLOD::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, Mesh** mesh)
|
||||
{
|
||||
bool result = false;
|
||||
Real closest = MAX_Real;
|
||||
Vector3 closestNormal = Vector3::Up;
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Real dst;
|
||||
Vector3 nrm;
|
||||
if (Meshes[i].Intersects(ray, transform, dst, nrm) && dst < closest)
|
||||
{
|
||||
result = true;
|
||||
*mesh = &Meshes[i];
|
||||
closest = dst;
|
||||
closestNormal = nrm;
|
||||
}
|
||||
}
|
||||
distance = closest;
|
||||
normal = closestNormal;
|
||||
return result;
|
||||
}
|
||||
|
||||
BoundingBox ModelLOD::GetBox(const Matrix& world) const
|
||||
{
|
||||
Vector3 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
|
||||
Vector3 corners[8];
|
||||
for (int32 meshIndex = 0; meshIndex < Meshes.Count(); meshIndex++)
|
||||
{
|
||||
const auto& mesh = Meshes[meshIndex];
|
||||
mesh.GetBox().GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
Vector3::Transform(corners[i], world, tmp);
|
||||
min = Vector3::Min(min, tmp);
|
||||
max = Vector3::Max(max, tmp);
|
||||
}
|
||||
}
|
||||
return BoundingBox(min, max);
|
||||
}
|
||||
|
||||
BoundingBox ModelLOD::GetBox(const Transform& transform, const MeshDeformation* deformation) const
|
||||
{
|
||||
Vector3 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
|
||||
Vector3 corners[8];
|
||||
for (int32 meshIndex = 0; meshIndex < Meshes.Count(); meshIndex++)
|
||||
{
|
||||
const auto& mesh = Meshes[meshIndex];
|
||||
BoundingBox box = mesh.GetBox();
|
||||
if (deformation)
|
||||
deformation->GetBounds(_lodIndex, meshIndex, box);
|
||||
box.GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
transform.LocalToWorld(corners[i], tmp);
|
||||
min = Vector3::Min(min, tmp);
|
||||
max = Vector3::Max(max, tmp);
|
||||
}
|
||||
}
|
||||
return BoundingBox(min, max);
|
||||
}
|
||||
|
||||
BoundingBox ModelLOD::GetBox() const
|
||||
{
|
||||
Vector3 min = Vector3::Maximum, max = Vector3::Minimum;
|
||||
Vector3 corners[8];
|
||||
for (int32 meshIndex = 0; meshIndex < Meshes.Count(); meshIndex++)
|
||||
{
|
||||
Meshes[meshIndex].GetBox().GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
min = Vector3::Min(min, corners[i]);
|
||||
max = Vector3::Max(max, corners[i]);
|
||||
}
|
||||
}
|
||||
return BoundingBox(min, max);
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Mesh.h"
|
||||
|
||||
class MemoryReadStream;
|
||||
@@ -18,7 +17,14 @@ API_CLASS(NoSpawn) class FLAXENGINE_API ModelLOD : public ScriptingObject
|
||||
private:
|
||||
Model* _model = nullptr;
|
||||
int32 _lodIndex = 0;
|
||||
uint32 _verticesCount;
|
||||
uint32 _verticesCount = 0;
|
||||
|
||||
void Link(Model* model, int32 lodIndex)
|
||||
{
|
||||
_model = model;
|
||||
_lodIndex = lodIndex;
|
||||
_verticesCount = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -57,24 +63,6 @@ public:
|
||||
return _verticesCount;
|
||||
}
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes the LOD from the data stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream.</param>
|
||||
/// <returns>True if fails, otherwise false.</returns>
|
||||
bool Load(MemoryReadStream& stream);
|
||||
|
||||
/// <summary>
|
||||
/// Unloads the LOD meshes data (vertex buffers and cache). It won't dispose the meshes collection. The opposite to Load.
|
||||
/// </summary>
|
||||
void Unload();
|
||||
|
||||
/// <summary>
|
||||
/// Cleanups the data.
|
||||
/// </summary>
|
||||
void Dispose();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Determines if there is an intersection between the Model and a Ray in given world using given instance
|
||||
|
||||
@@ -94,71 +94,17 @@ void SkeletonData::Dispose()
|
||||
Bones.Resize(0);
|
||||
}
|
||||
|
||||
void SkinnedMesh::Init(SkinnedModel* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere)
|
||||
{
|
||||
_model = model;
|
||||
_index = index;
|
||||
_lodIndex = lodIndex;
|
||||
_materialSlotIndex = materialSlotIndex;
|
||||
_use16BitIndexBuffer = false;
|
||||
_box = box;
|
||||
_sphere = sphere;
|
||||
_vertices = 0;
|
||||
_triangles = 0;
|
||||
_vertexBuffers[0] = nullptr;
|
||||
_indexBuffer = nullptr;
|
||||
_cachedIndexBuffer.Clear();
|
||||
_cachedVertexBuffers[0].Clear();
|
||||
BlendShapes.Clear();
|
||||
}
|
||||
|
||||
bool SkinnedMesh::Load(uint32 vertices, uint32 triangles, const void* vb0, const void* ib, bool use16BitIndexBuffer)
|
||||
{
|
||||
// Cache data
|
||||
uint32 indicesCount = triangles * 3;
|
||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
|
||||
GPUBuffer* vertexBuffer = nullptr;
|
||||
GPUBuffer* indexBuffer = nullptr;
|
||||
|
||||
// Create vertex buffer
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
vertexBuffer = GPUDevice::Instance->CreateBuffer(GetSkinnedModel()->GetPath() + TEXT(".VB"));
|
||||
#else
|
||||
vertexBuffer = GPUDevice::Instance->CreateBuffer(String::Empty);
|
||||
#endif
|
||||
if (vertexBuffer->Init(GPUBufferDescription::Vertex(VB0SkinnedElementType::GetLayout(), sizeof(VB0SkinnedElementType), vertices, vb0)))
|
||||
goto ERROR_LOAD_END;
|
||||
|
||||
// Create index buffer
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
indexBuffer = GPUDevice::Instance->CreateBuffer(GetSkinnedModel()->GetPath() + TEXT(".IB"));
|
||||
#else
|
||||
indexBuffer = GPUDevice::Instance->CreateBuffer(String::Empty);
|
||||
#endif
|
||||
if (indexBuffer->Init(GPUBufferDescription::Index(ibStride, indicesCount, ib)))
|
||||
goto ERROR_LOAD_END;
|
||||
|
||||
// Initialize
|
||||
_vertexBuffers[0] = vertexBuffer;
|
||||
_indexBuffer = indexBuffer;
|
||||
_triangles = triangles;
|
||||
_vertices = vertices;
|
||||
_use16BitIndexBuffer = use16BitIndexBuffer;
|
||||
|
||||
return false;
|
||||
|
||||
ERROR_LOAD_END:
|
||||
|
||||
SAFE_DELETE_GPU_RESOURCE(vertexBuffer);
|
||||
SAFE_DELETE_GPU_RESOURCE(indexBuffer);
|
||||
return true;
|
||||
Array<const void*, FixedAllocation<3>> vbData;
|
||||
vbData.Add(vb0);
|
||||
Array<GPUVertexLayout*, FixedAllocation<3>> vbLayout;
|
||||
vbLayout.Add(VB0SkinnedElementType::GetLayout());
|
||||
return Init(vertices, triangles, vbData, ib, use16BitIndexBuffer, vbLayout);
|
||||
}
|
||||
|
||||
bool SkinnedMesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const VB0SkinnedElementType* vb, const void* ib, bool use16BitIndices)
|
||||
{
|
||||
auto model = (SkinnedModel*)_model;
|
||||
|
||||
// Setup GPU resources
|
||||
const bool failed = Load(vertexCount, triangleCount, vb, ib, use16BitIndices);
|
||||
if (!failed)
|
||||
@@ -167,11 +113,7 @@ bool SkinnedMesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, const VB0
|
||||
BoundingBox bounds;
|
||||
BoundingBox::FromPoints((const Float3*)vb, vertexCount, bounds);
|
||||
SetBounds(bounds);
|
||||
|
||||
// Send event (actors using this model can update bounds, etc.)
|
||||
model->onLoaded();
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
@@ -267,6 +209,13 @@ void SkinnedMesh::Draw(const RenderContextBatch& renderContextBatch, const DrawI
|
||||
renderContextBatch.GetMainContext().List->AddDrawCall(renderContextBatch, drawModes, StaticFlags::None, shadowsMode, info.Bounds, drawCall, entry.ReceiveDecals, info.SortOrder);
|
||||
}
|
||||
|
||||
void SkinnedMesh::Release()
|
||||
{
|
||||
MeshBase::Release();
|
||||
|
||||
BlendShapes.Clear();
|
||||
}
|
||||
|
||||
bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const
|
||||
{
|
||||
if (_cachedVertexBuffers[0].IsEmpty())
|
||||
|
||||
@@ -36,19 +36,9 @@ public:
|
||||
Array<BlendShape> BlendShapes;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SkinnedMesh"/> class.
|
||||
/// </summary>
|
||||
/// <param name="model">The model.</param>
|
||||
/// <param name="lodIndex">The model LOD index.</param>
|
||||
/// <param name="index">The mesh index.</param>
|
||||
/// <param name="materialSlotIndex">The material slot index to use.</param>
|
||||
/// <param name="box">The bounding box.</param>
|
||||
/// <param name="sphere">The bounding sphere.</param>
|
||||
void Init(SkinnedModel* model, int32 lodIndex, int32 index, int32 materialSlotIndex, const BoundingBox& box, const BoundingSphere& sphere);
|
||||
|
||||
/// <summary>
|
||||
/// Load mesh data and Initialize GPU buffers
|
||||
/// [Deprecated in v1.10]
|
||||
/// </summary>
|
||||
/// <param name="vertices">Amount of vertices in the vertex buffer</param>
|
||||
/// <param name="triangles">Amount of triangles in the index buffer</param>
|
||||
@@ -56,7 +46,7 @@ public:
|
||||
/// <param name="ib">Index buffer data</param>
|
||||
/// <param name="use16BitIndexBuffer">True if use 16 bit indices for the index buffer (true: uint16, false: uint32).</param>
|
||||
/// <returns>True if cannot load data, otherwise false.</returns>
|
||||
bool Load(uint32 vertices, uint32 triangles, const void* vb0, const void* ib, bool use16BitIndexBuffer);
|
||||
DEPRECATED("Use Init intead.") bool Load(uint32 vertices, uint32 triangles, const void* vb0, const void* ib, bool use16BitIndexBuffer);
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
@@ -128,6 +118,7 @@ public:
|
||||
|
||||
public:
|
||||
// [MeshBase]
|
||||
void Release() override;
|
||||
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "SkinnedModelLOD.h"
|
||||
#include "MeshDeformation.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
|
||||
bool SkinnedModelLOD::Load(MemoryReadStream& stream)
|
||||
{
|
||||
// Load LOD for each mesh
|
||||
byte version = stream.ReadByte();
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
auto& mesh = Meshes[i];
|
||||
|
||||
// #MODEL_DATA_FORMAT_USAGE
|
||||
uint32 vertices;
|
||||
stream.ReadUint32(&vertices);
|
||||
uint32 triangles;
|
||||
stream.ReadUint32(&triangles);
|
||||
uint16 blendShapesCount;
|
||||
stream.ReadUint16(&blendShapesCount);
|
||||
if (blendShapesCount != mesh.BlendShapes.Count())
|
||||
{
|
||||
LOG(Warning, "Cannot initialize mesh {0}. Incorect blend shapes amount: {1} (expected: {2})", i, blendShapesCount, mesh.BlendShapes.Count());
|
||||
return true;
|
||||
}
|
||||
for (auto& blendShape : mesh.BlendShapes)
|
||||
{
|
||||
blendShape.UseNormals = stream.ReadBool();
|
||||
stream.ReadUint32(&blendShape.MinVertexIndex);
|
||||
stream.ReadUint32(&blendShape.MaxVertexIndex);
|
||||
uint32 blendShapeVertices;
|
||||
stream.ReadUint32(&blendShapeVertices);
|
||||
blendShape.Vertices.Resize(blendShapeVertices);
|
||||
stream.ReadBytes(blendShape.Vertices.Get(), blendShape.Vertices.Count() * sizeof(BlendShapeVertex));
|
||||
}
|
||||
const uint32 indicesCount = triangles * 3;
|
||||
const bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
||||
const uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||
if (vertices == 0 || triangles == 0)
|
||||
return true;
|
||||
const auto vb0 = stream.Move<VB0SkinnedElementType>(vertices);
|
||||
const auto ib = stream.Move<byte>(indicesCount * ibStride);
|
||||
|
||||
// Setup GPU resources
|
||||
if (mesh.Load(vertices, triangles, vb0, ib, use16BitIndexBuffer))
|
||||
{
|
||||
LOG(Warning, "Cannot initialize mesh {0}. Vertices: {1}, triangles: {2}", i, vertices, triangles);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SkinnedModelLOD::Unload()
|
||||
{
|
||||
// Unload LOD for each mesh
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
Meshes[i].Unload();
|
||||
}
|
||||
}
|
||||
|
||||
void SkinnedModelLOD::Dispose()
|
||||
{
|
||||
_model = nullptr;
|
||||
ScreenSize = 0.0f;
|
||||
Meshes.Resize(0);
|
||||
}
|
||||
|
||||
bool SkinnedModelLOD::Intersects(const Ray& ray, const Matrix& world, Real& distance, Vector3& normal, SkinnedMesh** mesh)
|
||||
{
|
||||
// Check all meshes
|
||||
bool result = false;
|
||||
Real closest = MAX_float;
|
||||
Vector3 closestNormal = Vector3::Up;
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
// Test intersection with mesh and check if is closer than previous
|
||||
Real dst;
|
||||
Vector3 nrm;
|
||||
if (Meshes[i].Intersects(ray, world, dst, nrm) && dst < closest)
|
||||
{
|
||||
result = true;
|
||||
*mesh = &Meshes[i];
|
||||
closest = dst;
|
||||
closestNormal = nrm;
|
||||
}
|
||||
}
|
||||
|
||||
distance = closest;
|
||||
normal = closestNormal;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SkinnedModelLOD::Intersects(const Ray& ray, const Transform& transform, Real& distance, Vector3& normal, SkinnedMesh** mesh)
|
||||
{
|
||||
// Check all meshes
|
||||
bool result = false;
|
||||
Real closest = MAX_float;
|
||||
Vector3 closestNormal = Vector3::Up;
|
||||
for (int32 i = 0; i < Meshes.Count(); i++)
|
||||
{
|
||||
// Test intersection with mesh and check if is closer than previous
|
||||
Real dst;
|
||||
Vector3 nrm;
|
||||
if (Meshes[i].Intersects(ray, transform, dst, nrm) && dst < closest)
|
||||
{
|
||||
result = true;
|
||||
*mesh = &Meshes[i];
|
||||
closest = dst;
|
||||
closestNormal = nrm;
|
||||
}
|
||||
}
|
||||
|
||||
distance = closest;
|
||||
normal = closestNormal;
|
||||
return result;
|
||||
}
|
||||
|
||||
BoundingBox SkinnedModelLOD::GetBox(const Matrix& world) const
|
||||
{
|
||||
// Find minimum and maximum points of all the meshes
|
||||
Vector3 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
|
||||
Vector3 corners[8];
|
||||
for (int32 j = 0; j < Meshes.Count(); j++)
|
||||
{
|
||||
const auto& mesh = Meshes[j];
|
||||
mesh.GetBox().GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
Vector3::Transform(corners[i], world, tmp);
|
||||
min = Vector3::Min(min, tmp);
|
||||
max = Vector3::Max(max, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return BoundingBox(min, max);
|
||||
}
|
||||
|
||||
BoundingBox SkinnedModelLOD::GetBox(const Transform& transform, const MeshDeformation* deformation) const
|
||||
{
|
||||
Vector3 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
|
||||
Vector3 corners[8];
|
||||
for (int32 meshIndex = 0; meshIndex < Meshes.Count(); meshIndex++)
|
||||
{
|
||||
const auto& mesh = Meshes[meshIndex];
|
||||
BoundingBox box = mesh.GetBox();
|
||||
if (deformation)
|
||||
deformation->GetBounds(_lodIndex, meshIndex, box);
|
||||
box.GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
transform.LocalToWorld(corners[i], tmp);
|
||||
min = Vector3::Min(min, tmp);
|
||||
max = Vector3::Max(max, tmp);
|
||||
}
|
||||
}
|
||||
return BoundingBox(min, max);
|
||||
}
|
||||
|
||||
BoundingBox SkinnedModelLOD::GetBox(const Matrix& world, int32 meshIndex) const
|
||||
{
|
||||
// Find minimum and maximum points of the mesh
|
||||
Vector3 tmp, min = Vector3::Maximum, max = Vector3::Minimum;
|
||||
Vector3 corners[8];
|
||||
const auto& mesh = Meshes[meshIndex];
|
||||
mesh.GetBox().GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
Vector3::Transform(corners[i], world, tmp);
|
||||
min = Vector3::Min(min, tmp);
|
||||
max = Vector3::Max(max, tmp);
|
||||
}
|
||||
|
||||
return BoundingBox(min, max);
|
||||
}
|
||||
|
||||
BoundingBox SkinnedModelLOD::GetBox() const
|
||||
{
|
||||
// Find minimum and maximum points of the mesh in given world
|
||||
Vector3 min = Vector3::Maximum, max = Vector3::Minimum;
|
||||
Vector3 corners[8];
|
||||
for (int32 j = 0; j < Meshes.Count(); j++)
|
||||
{
|
||||
Meshes[j].GetBox().GetCorners(corners);
|
||||
for (int32 i = 0; i < 8; i++)
|
||||
{
|
||||
min = Vector3::Min(min, corners[i]);
|
||||
max = Vector3::Max(max, corners[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return BoundingBox(min, max);
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "SkinnedMesh.h"
|
||||
|
||||
class MemoryReadStream;
|
||||
@@ -46,23 +45,6 @@ public:
|
||||
return Meshes.HasItems() && Meshes.Last().IsInitialized();
|
||||
}
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Initializes the LOD from the data stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream.</param>
|
||||
/// <returns>True if fails, otherwise false.</returns>
|
||||
bool Load(MemoryReadStream& stream);
|
||||
|
||||
/// <summary>
|
||||
/// Unloads the LOD meshes data (vertex buffers and cache). It won't dispose the meshes collection. The opposite to Load.
|
||||
/// </summary>
|
||||
void Unload();
|
||||
|
||||
/// <summary>
|
||||
/// Cleanups the data.
|
||||
/// </summary>
|
||||
void Dispose();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -87,8 +87,8 @@ void GPUVertexLayout::SetElements(const Elements& elements, uint32 offsets[GPU_M
|
||||
strides[e.Slot] = Math::Max(strides[e.Slot], offsets[e.Slot]);
|
||||
}
|
||||
_stride = 0;
|
||||
for (int32 i = 0; i < GPU_MAX_VB_BINDED; i++)
|
||||
_stride += strides[i];
|
||||
for (uint32 stride : strides)
|
||||
_stride += stride;
|
||||
}
|
||||
|
||||
GPUVertexLayout* GPUVertexLayout::Get(const Elements& elements)
|
||||
|
||||
Reference in New Issue
Block a user