Implement DownloadDataCPU for Mesh and add result entries count
This commit is contained in:
@@ -5,16 +5,6 @@
|
||||
#include "ModelBase.h"
|
||||
#include "Engine/Graphics/Models/ModelLOD.h"
|
||||
|
||||
// Note: we use the first chunk as a header, next is the highest quality lod and then lower ones
|
||||
//
|
||||
// Example:
|
||||
// Chunk 0: Header
|
||||
// Chunk 1: LOD0
|
||||
// Chunk 2: LOD1
|
||||
// ..
|
||||
//
|
||||
#define MODEL_LOD_TO_CHUNK_INDEX(lod) (lod + 1)
|
||||
|
||||
class Mesh;
|
||||
class StreamModelLODTask;
|
||||
|
||||
|
||||
@@ -7,6 +7,16 @@
|
||||
#include "Engine/Graphics/Models/MaterialSlot.h"
|
||||
#include "Engine/Streaming/StreamableResource.h"
|
||||
|
||||
// Note: we use the first chunk as a header, next is the highest quality lod and then lower ones
|
||||
//
|
||||
// Example:
|
||||
// Chunk 0: Header
|
||||
// Chunk 1: LOD0
|
||||
// Chunk 2: LOD1
|
||||
// ..
|
||||
//
|
||||
#define MODEL_LOD_TO_CHUNK_INDEX(lod) (lod + 1)
|
||||
|
||||
class MeshBase;
|
||||
|
||||
/// <summary>
|
||||
@@ -58,7 +68,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets amount of the level of details in the model.
|
||||
/// </summary>
|
||||
/// <returns>Amount of the level of details in the model.</returns>
|
||||
virtual int32 GetLODsCount() const = 0;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -147,13 +147,13 @@ Array<String> SkinnedModel::GetBlendShapes()
|
||||
|
||||
ContentLoadTask* SkinnedModel::RequestLODDataAsync(int32 lodIndex)
|
||||
{
|
||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
const int32 chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
return RequestChunkDataAsync(chunkIndex);
|
||||
}
|
||||
|
||||
void SkinnedModel::GetLODData(int32 lodIndex, BytesContainer& data) const
|
||||
{
|
||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
const int32 chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
GetChunkData(chunkIndex, data);
|
||||
}
|
||||
|
||||
@@ -617,7 +617,7 @@ bool SkinnedModel::Save(bool withMeshDataFromGpu, const StringView& path)
|
||||
}
|
||||
|
||||
// Override meshes data chunk with the fetched GPU meshes memory
|
||||
auto lodChunk = GET_CHUNK(SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex));
|
||||
auto lodChunk = GET_CHUNK(MODEL_LOD_TO_CHUNK_INDEX(lodIndex));
|
||||
if (lodChunk == nullptr)
|
||||
return true;
|
||||
lodChunk->Data.Copy(meshesStream.GetHandle(), meshesStream.GetPosition());
|
||||
@@ -631,7 +631,7 @@ bool SkinnedModel::Save(bool withMeshDataFromGpu, const StringView& path)
|
||||
// Load all chunks with a mesh data
|
||||
for (int32 lodIndex = 0; lodIndex < LODs.Count(); lodIndex++)
|
||||
{
|
||||
if (LoadChunk(SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex)))
|
||||
if (LoadChunk(MODEL_LOD_TO_CHUNK_INDEX(lodIndex)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,16 +9,6 @@
|
||||
|
||||
class StreamSkinnedModelLODTask;
|
||||
|
||||
// Note: we use the first chunk as a header, next is the highest quality lod and then lower ones
|
||||
//
|
||||
// Example:
|
||||
// Chunk 0: Header
|
||||
// Chunk 1: LOD0
|
||||
// Chunk 2: LOD1
|
||||
// ..
|
||||
//
|
||||
#define SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lod) (lod + 1)
|
||||
|
||||
/// <summary>
|
||||
/// Skinned model asset that contains model object made of meshes that can be rendered on the GPU using skeleton bones skinning.
|
||||
/// </summary>
|
||||
|
||||
@@ -78,11 +78,11 @@ void BlendShapesInstance::Update(SkinnedModel* skinnedModel)
|
||||
if (!instance.IsUsed)
|
||||
continue;
|
||||
const SkinnedMesh* mesh = e.Key;
|
||||
const int32 vertexCount = mesh->GetVertexCount();
|
||||
|
||||
// Get skinned mesh vertex buffer data (original, cached on CPU)
|
||||
BytesContainer vertexBuffer;
|
||||
if (mesh->DownloadDataCPU(MeshBufferType::Vertex0, vertexBuffer))
|
||||
int32 vertexCount;
|
||||
if (mesh->DownloadDataCPU(MeshBufferType::Vertex0, vertexBuffer, vertexCount))
|
||||
{
|
||||
// Don't use this mesh if failed to get it's vertices data
|
||||
instance.IsUsed = false;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Level/Scene/Scene.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
@@ -293,6 +293,9 @@ bool Mesh::Load(uint32 vertices, uint32 triangles, void* vb0, void* vb1, void* v
|
||||
_triangles = triangles;
|
||||
_vertices = vertices;
|
||||
_use16BitIndexBuffer = use16BitIndexBuffer;
|
||||
_cachedVertexBuffer[0].Clear();
|
||||
_cachedVertexBuffer[1].Clear();
|
||||
_cachedVertexBuffer[2].Clear();
|
||||
|
||||
return false;
|
||||
|
||||
@@ -314,6 +317,10 @@ void Mesh::Unload()
|
||||
_triangles = 0;
|
||||
_vertices = 0;
|
||||
_use16BitIndexBuffer = false;
|
||||
_cachedIndexBuffer.Resize(0);
|
||||
_cachedVertexBuffer[0].Clear();
|
||||
_cachedVertexBuffer[1].Clear();
|
||||
_cachedVertexBuffer[2].Clear();
|
||||
}
|
||||
|
||||
bool Mesh::Intersects(const Ray& ray, const Matrix& world, float& distance, Vector3& normal) const
|
||||
@@ -506,13 +513,94 @@ Task* Mesh::DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) co
|
||||
return buffer ? buffer->DownloadDataAsync(result) : nullptr;
|
||||
}
|
||||
|
||||
bool Mesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) const
|
||||
bool Mesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const
|
||||
{
|
||||
#if !BUILD_RELEASE
|
||||
// TODO: implement this
|
||||
LOG(Error, "Mesh::DownloadDataCPU not implemented.");
|
||||
#endif
|
||||
return true;
|
||||
if (_cachedVertexBuffer[0].IsEmpty())
|
||||
{
|
||||
PROFILE_CPU();
|
||||
auto model = GetModel();
|
||||
ScopeLock lock(model->Locker);
|
||||
if (model->IsVirtual())
|
||||
{
|
||||
LOG(Error, "Cannot access CPU data of virtual models. Use GPU data download");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch chunk with data from drive/memory
|
||||
const auto chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(GetLODIndex());
|
||||
if (model->LoadChunk(chunkIndex))
|
||||
return true;
|
||||
const auto chunk = model->GetChunk(chunkIndex);
|
||||
if (!chunk)
|
||||
{
|
||||
LOG(Error, "Missing chunk.");
|
||||
return true;
|
||||
}
|
||||
|
||||
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
||||
|
||||
// Seek to find mesh location
|
||||
for (int32 i = 0; i <= _index; i++)
|
||||
{
|
||||
// #MODEL_DATA_FORMAT_USAGE
|
||||
uint32 vertices;
|
||||
stream.ReadUint32(&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)
|
||||
{
|
||||
LOG(Error, "Invalid mesh data.");
|
||||
return true;
|
||||
}
|
||||
auto vb0 = stream.Read<VB0ElementType>(vertices);
|
||||
auto vb1 = stream.Read<VB1ElementType>(vertices);
|
||||
bool hasColors = stream.ReadBool();
|
||||
VB2ElementType18* vb2 = nullptr;
|
||||
if (hasColors)
|
||||
{
|
||||
vb2 = stream.Read<VB2ElementType18>(vertices);
|
||||
}
|
||||
auto ib = stream.Read<byte>(indicesCount * ibStride);
|
||||
|
||||
if (i != _index)
|
||||
continue;
|
||||
|
||||
// Cache mesh data
|
||||
_cachedIndexBufferCount = indicesCount;
|
||||
_cachedIndexBuffer.Set(ib, indicesCount * ibStride);
|
||||
_cachedVertexBuffer[0].Set((const byte*)vb0, vertices * sizeof(VB0ElementType));
|
||||
_cachedVertexBuffer[1].Set((const byte*)vb1, vertices * sizeof(VB1ElementType));
|
||||
if (hasColors)
|
||||
_cachedVertexBuffer[2].Set((const byte*)vb2, vertices * sizeof(VB2ElementType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MeshBufferType::Index:
|
||||
result.Link(_cachedIndexBuffer);
|
||||
count = _cachedIndexBufferCount;
|
||||
break;
|
||||
case MeshBufferType::Vertex0:
|
||||
result.Link(_cachedVertexBuffer[0]);
|
||||
count = _cachedVertexBuffer[0].Count() / sizeof(VB0ElementType);
|
||||
break;
|
||||
case MeshBufferType::Vertex1:
|
||||
result.Link(_cachedVertexBuffer[1]);
|
||||
count = _cachedVertexBuffer[1].Count() / sizeof(VB1ElementType);
|
||||
break;
|
||||
case MeshBufferType::Vertex2:
|
||||
result.Link(_cachedVertexBuffer[2]);
|
||||
count = _cachedVertexBuffer[2].Count() / sizeof(VB2ElementType);
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptingObject* Mesh::GetParentModel()
|
||||
@@ -645,145 +733,50 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if load data from GPU
|
||||
MeshBufferType bufferType;
|
||||
switch (type)
|
||||
{
|
||||
case InternalBufferType::VB0:
|
||||
bufferType = MeshBufferType::Vertex0;
|
||||
break;
|
||||
case InternalBufferType::VB1:
|
||||
bufferType = MeshBufferType::Vertex1;
|
||||
break;
|
||||
case InternalBufferType::VB2:
|
||||
bufferType = MeshBufferType::Vertex2;
|
||||
break;
|
||||
case InternalBufferType::IB16:
|
||||
case InternalBufferType::IB32:
|
||||
bufferType = MeshBufferType::Index;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
BytesContainer data;
|
||||
if (forceGpu)
|
||||
{
|
||||
MeshBufferType bufferType;
|
||||
switch (type)
|
||||
{
|
||||
case InternalBufferType::VB0:
|
||||
bufferType = MeshBufferType::Vertex0;
|
||||
break;
|
||||
case InternalBufferType::VB1:
|
||||
bufferType = MeshBufferType::Vertex1;
|
||||
break;
|
||||
case InternalBufferType::VB2:
|
||||
bufferType = MeshBufferType::Vertex2;
|
||||
break;
|
||||
case InternalBufferType::IB16:
|
||||
case InternalBufferType::IB32:
|
||||
bufferType = MeshBufferType::Index;
|
||||
break;
|
||||
default: CRASH;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get data from GPU
|
||||
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
|
||||
BytesContainer data;
|
||||
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
|
||||
model->Locker.Unlock();
|
||||
|
||||
task->Start();
|
||||
model->Locker.Unlock();
|
||||
if (task->Wait())
|
||||
{
|
||||
LOG(Error, "Task failed.");
|
||||
return true;
|
||||
}
|
||||
|
||||
ConvertMeshData(mesh, type, resultObj, data.Get());
|
||||
|
||||
model->Locker.Lock();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get data from drive/memory
|
||||
else
|
||||
{
|
||||
// Fetch chunk with data
|
||||
const auto chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(mesh->GetLODIndex());
|
||||
if (model->LoadChunk(chunkIndex))
|
||||
// Get data from CPU
|
||||
int32 count;
|
||||
if (DownloadDataCPU(bufferType, data, count))
|
||||
return true;
|
||||
const auto chunk = model->GetChunk(chunkIndex);
|
||||
if (!chunk)
|
||||
{
|
||||
LOG(Error, "Missing chunk.");
|
||||
return true;
|
||||
}
|
||||
|
||||
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
||||
|
||||
// Seek to find mesh location
|
||||
for (int32 i = 0; i < mesh->GetIndex(); i++)
|
||||
{
|
||||
// #MODEL_DATA_FORMAT_USAGE
|
||||
uint32 vertices;
|
||||
stream.ReadUint32(&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)
|
||||
{
|
||||
LOG(Error, "Invalid mesh data.");
|
||||
return true;
|
||||
}
|
||||
auto vb0 = stream.Read<VB0ElementType>(vertices);
|
||||
auto vb1 = stream.Read<VB1ElementType>(vertices);
|
||||
bool hasColors = stream.ReadBool();
|
||||
VB2ElementType18* vb2 = nullptr;
|
||||
if (hasColors)
|
||||
{
|
||||
vb2 = stream.Read<VB2ElementType18>(vertices);
|
||||
}
|
||||
auto ib = stream.Read<byte>(indicesCount * ibStride);
|
||||
}
|
||||
|
||||
// Get mesh data
|
||||
void* data = nullptr;
|
||||
{
|
||||
// #MODEL_DATA_FORMAT_USAGE
|
||||
uint32 vertices;
|
||||
stream.ReadUint32(&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)
|
||||
{
|
||||
LOG(Error, "Invalid mesh data.");
|
||||
return true;
|
||||
}
|
||||
auto vb0 = stream.Read<VB0ElementType>(vertices);
|
||||
auto vb1 = stream.Read<VB1ElementType>(vertices);
|
||||
bool hasColors = stream.ReadBool();
|
||||
VB2ElementType18* vb2 = nullptr;
|
||||
if (hasColors)
|
||||
{
|
||||
vb2 = stream.Read<VB2ElementType18>(vertices);
|
||||
}
|
||||
auto ib = stream.Read<byte>(indicesCount * ibStride);
|
||||
|
||||
if (mesh->HasVertexColors() != hasColors || mesh->Use16BitIndexBuffer() != use16BitIndexBuffer)
|
||||
{
|
||||
LOG(Error, "Invalid mesh data loaded from chunk.");
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case InternalBufferType::VB0:
|
||||
data = vb0;
|
||||
break;
|
||||
case InternalBufferType::VB1:
|
||||
data = vb1;
|
||||
break;
|
||||
case InternalBufferType::VB2:
|
||||
data = vb2;
|
||||
break;
|
||||
case InternalBufferType::IB16:
|
||||
case InternalBufferType::IB32:
|
||||
data = ib;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ConvertMeshData(mesh, type, resultObj, data);
|
||||
}
|
||||
|
||||
ConvertMeshData(mesh, type, resultObj, data.Get());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ API_CLASS(NoSpawn) class FLAXENGINE_API Mesh : public MeshBase
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(Mesh, MeshBase);
|
||||
protected:
|
||||
|
||||
int32 _index;
|
||||
int32 _lodIndex;
|
||||
bool _hasLightmapUVs;
|
||||
@@ -30,8 +31,12 @@ protected:
|
||||
#if USE_PRECISE_MESH_INTERSECTS
|
||||
CollisionProxy _collisionProxy;
|
||||
#endif
|
||||
mutable Array<byte> _cachedVertexBuffer[3];
|
||||
mutable Array<byte> _cachedIndexBuffer;
|
||||
mutable int32 _cachedIndexBufferCount;
|
||||
|
||||
public:
|
||||
|
||||
Mesh(const Mesh& other)
|
||||
: Mesh()
|
||||
{
|
||||
@@ -46,6 +51,7 @@ public:
|
||||
~Mesh();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model owning this mesh.
|
||||
/// </summary>
|
||||
@@ -92,7 +98,6 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this mesh is initialized (has vertex and index buffers initialized).
|
||||
/// </summary>
|
||||
/// <returns>True if this instance is initialized, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsInitialized() const
|
||||
{
|
||||
return _vertexBuffers[0] != nullptr;
|
||||
@@ -101,13 +106,11 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this mesh has a vertex colors buffer.
|
||||
/// </summary>
|
||||
/// <returns>True if this mesh has a vertex colors buffers.</returns>
|
||||
API_PROPERTY() bool HasVertexColors() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this mesh contains valid lightmap texture coordinates data.
|
||||
/// </summary>
|
||||
/// <returns>True if this mesh has a vertex colors buffers.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool HasLightmapUVs() const
|
||||
{
|
||||
return _hasLightmapUVs;
|
||||
@@ -118,7 +121,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the collision proxy used by the mesh.
|
||||
/// </summary>
|
||||
/// <returns>The collisions proxy container object reference.</returns>
|
||||
FORCE_INLINE const CollisionProxy& GetCollisionProxy() const
|
||||
{
|
||||
return _collisionProxy;
|
||||
@@ -127,6 +129,7 @@ public:
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
||||
/// </summary>
|
||||
@@ -205,6 +208,7 @@ public:
|
||||
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Updates the model mesh index buffer (used by the virtual models created with Init rather than Load).
|
||||
/// </summary>
|
||||
@@ -237,6 +241,7 @@ public:
|
||||
bool UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes instance of the <see cref="Mesh"/> class.
|
||||
/// </summary>
|
||||
@@ -268,6 +273,7 @@ public:
|
||||
void Unload();
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Determines if there is an intersection between the mesh and a ray in given world
|
||||
/// </summary>
|
||||
@@ -288,6 +294,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the draw call geometry for this mesh. Sets the index and vertex buffers.
|
||||
/// </summary>
|
||||
@@ -387,12 +394,14 @@ public:
|
||||
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) const override;
|
||||
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const override;
|
||||
|
||||
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);
|
||||
|
||||
@@ -45,7 +45,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the triangle count.
|
||||
/// </summary>
|
||||
/// <returns>The triangles</returns>
|
||||
API_PROPERTY() FORCE_INLINE int32 GetTriangleCount() const
|
||||
{
|
||||
return _triangles;
|
||||
@@ -54,7 +53,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the vertex count.
|
||||
/// </summary>
|
||||
/// <returns>The vertices</returns>
|
||||
API_PROPERTY() FORCE_INLINE int32 GetVertexCount() const
|
||||
{
|
||||
return _vertices;
|
||||
@@ -63,7 +61,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the box.
|
||||
/// </summary>
|
||||
/// <returns>The bounding box.</returns>
|
||||
API_PROPERTY() FORCE_INLINE const BoundingBox& GetBox() const
|
||||
{
|
||||
return _box;
|
||||
@@ -72,7 +69,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the sphere.
|
||||
/// </summary>
|
||||
/// <returns>The bounding sphere.</returns>
|
||||
API_PROPERTY() FORCE_INLINE const BoundingSphere& GetSphere() const
|
||||
{
|
||||
return _sphere;
|
||||
@@ -129,6 +125,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="type">Buffer type</param>
|
||||
/// <param name="result">The result data</param>
|
||||
/// <param name="count">The amount of items inside the result buffer.</param>
|
||||
/// <returns>True if failed, otherwise false</returns>
|
||||
virtual bool DownloadDataCPU(MeshBufferType type, BytesContainer& result) const = 0;
|
||||
virtual bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const = 0;
|
||||
};
|
||||
|
||||
@@ -227,16 +227,21 @@ Task* SkinnedMesh::DownloadDataGPUAsync(MeshBufferType type, BytesContainer& res
|
||||
return buffer ? buffer->DownloadDataAsync(result) : nullptr;
|
||||
}
|
||||
|
||||
bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) const
|
||||
bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const
|
||||
{
|
||||
if (_cachedVertexBuffer.IsEmpty())
|
||||
{
|
||||
PROFILE_CPU();
|
||||
auto model = GetSkinnedModel();
|
||||
ScopeLock lock(model->Locker);
|
||||
if (model->IsVirtual())
|
||||
{
|
||||
LOG(Error, "Cannot access CPU data of virtual models. Use GPU data download");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch chunk with data from drive/memory
|
||||
const auto chunkIndex = _lodIndex + 1;
|
||||
const auto chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(_lodIndex);
|
||||
if (model->LoadChunk(chunkIndex))
|
||||
return true;
|
||||
const auto chunk = model->GetChunk(chunkIndex);
|
||||
@@ -283,6 +288,7 @@ bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) c
|
||||
continue;
|
||||
|
||||
// Cache mesh data
|
||||
_cachedIndexBufferCount = indicesCount;
|
||||
_cachedIndexBuffer.Set(ib, indicesCount * ibStride);
|
||||
_cachedVertexBuffer.Set((const byte*)vb0, vertices * sizeof(VB0SkinnedElementType));
|
||||
break;
|
||||
@@ -293,9 +299,11 @@ bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) c
|
||||
{
|
||||
case MeshBufferType::Index:
|
||||
result.Link(_cachedIndexBuffer);
|
||||
count = _cachedIndexBufferCount;
|
||||
break;
|
||||
case MeshBufferType::Vertex0:
|
||||
result.Link(_cachedVertexBuffer);
|
||||
count = _cachedVertexBuffer.Count() / sizeof(VB0SkinnedElementType);
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
@@ -533,16 +541,19 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
task->Start();
|
||||
model->Locker.Unlock();
|
||||
if (task->Wait())
|
||||
{
|
||||
LOG(Error, "Task failed.");
|
||||
return true;
|
||||
}
|
||||
model->Locker.Lock();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get data from CPU
|
||||
if (DownloadDataCPU(bufferType, data))
|
||||
int32 count;
|
||||
if (DownloadDataCPU(bufferType, data, count))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ protected:
|
||||
GPUBuffer* _indexBuffer;
|
||||
mutable Array<byte> _cachedIndexBuffer;
|
||||
mutable Array<byte> _cachedVertexBuffer;
|
||||
mutable int32 _cachedIndexBufferCount;
|
||||
|
||||
public:
|
||||
|
||||
@@ -46,7 +47,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the skinned model owning this mesh.
|
||||
/// </summary>
|
||||
/// <returns>The skinned model</returns>
|
||||
FORCE_INLINE SkinnedModel* GetSkinnedModel() const
|
||||
{
|
||||
return (SkinnedModel*)_model;
|
||||
@@ -55,7 +55,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the mesh index.
|
||||
/// </summary>
|
||||
/// <returns>The index</returns>
|
||||
FORCE_INLINE int32 GetIndex() const
|
||||
{
|
||||
return _index;
|
||||
@@ -64,7 +63,6 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this mesh is initialized (has vertex and index buffers initialized).
|
||||
/// </summary>
|
||||
/// <returns>True if this instance is initialized, otherwise false.</returns>
|
||||
FORCE_INLINE bool IsInitialized() const
|
||||
{
|
||||
return _vertexBuffer != nullptr;
|
||||
@@ -241,7 +239,7 @@ public:
|
||||
// [MeshBase]
|
||||
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
|
||||
Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const override;
|
||||
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result) const override;
|
||||
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user