diff --git a/Source/Engine/Graphics/Mesh.cs b/Source/Engine/Graphics/Mesh.cs
index d4f693e77..0a986d44d 100644
--- a/Source/Engine/Graphics/Mesh.cs
+++ b/Source/Engine/Graphics/Mesh.cs
@@ -527,9 +527,8 @@ namespace FlaxEngine
/// The gathered data.
public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false)
{
- var vertices = VertexCount;
- var result = new Vertex0[vertices];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0))
+ var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -541,9 +540,8 @@ namespace FlaxEngine
/// The gathered data.
public Vertex1[] DownloadVertexBuffer1(bool forceGpu = false)
{
- var vertices = VertexCount;
- var result = new Vertex1[vertices];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB1))
+ var result = (Vertex1[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex1), (int)InternalBufferType.VB1);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -560,10 +558,8 @@ namespace FlaxEngine
{
if (!HasVertexColors)
return null;
-
- var vertices = VertexCount;
- var result = new Vertex2[vertices];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB2))
+ var result = (Vertex2[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex2), (int)InternalBufferType.VB2);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -582,7 +578,7 @@ namespace FlaxEngine
var vb1 = DownloadVertexBuffer1(forceGpu);
var vb2 = DownloadVertexBuffer2(forceGpu);
- var vertices = VertexCount;
+ var vertices = vb0.Length;
var result = new Vertex[vertices];
for (int i = 0; i < vertices; i++)
{
@@ -618,9 +614,8 @@ namespace FlaxEngine
/// The gathered data.
public uint[] DownloadIndexBuffer(bool forceGpu = false)
{
- var triangles = TriangleCount;
- var result = new uint[triangles * 3];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32))
+ var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -633,9 +628,8 @@ namespace FlaxEngine
/// The gathered data.
public ushort[] DownloadIndexBufferUShort(bool forceGpu = false)
{
- var triangles = TriangleCount;
- var result = new ushort[triangles * 3];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16))
+ var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp
index 7b0130874..335b4cb69 100644
--- a/Source/Engine/Graphics/Models/Mesh.cpp
+++ b/Source/Engine/Graphics/Models/Mesh.cpp
@@ -746,75 +746,11 @@ enum class InternalBufferType
IB32 = 4,
};
-void ConvertMeshData(Mesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData)
+MonoArray* Mesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
{
- auto vertices = mesh->GetVertexCount();
- auto triangles = mesh->GetTriangleCount();
- auto indices = triangles * 3;
- auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer();
-
- void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0);
- switch (type)
- {
- case InternalBufferType::VB0:
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0ElementType) * vertices);
- break;
- }
- case InternalBufferType::VB1:
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB1ElementType) * vertices);
- break;
- }
- case InternalBufferType::VB2:
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB2ElementType) * vertices);
- break;
- }
- case InternalBufferType::IB16:
- {
- if (use16BitIndexBuffer)
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices);
- }
- else
- {
- auto dst = (uint16*)managedArrayPtr;
- auto src = (uint32*)srcData;
- for (int32 i = 0; i < indices; i++)
- {
- dst[i] = src[i];
- }
- }
- break;
- }
- case InternalBufferType::IB32:
- {
- if (use16BitIndexBuffer)
- {
- auto dst = (uint32*)managedArrayPtr;
- auto src = (uint16*)srcData;
- for (int32 i = 0; i < indices; i++)
- {
- dst[i] = src[i];
- }
- }
- else
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices);
- }
- break;
- }
- }
-}
-
-bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
-{
- Mesh* mesh = this;
- InternalBufferType type = (InternalBufferType)typeI;
+ auto mesh = this;
+ auto type = (InternalBufferType)typeI;
auto model = mesh->GetModel();
- ASSERT(model && resultObj);
-
ScopeLock lock(model->Locker);
// Virtual assets always fetch from GPU memory
@@ -823,23 +759,7 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
if (!mesh->IsInitialized() && forceGpu)
{
LOG(Error, "Cannot load mesh data from GPU if it's not loaded.");
- return true;
- }
- if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32)
- {
- if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3)
- {
- LOG(Error, "Invalid buffer size.");
- return true;
- }
- }
- else
- {
- if (mono_array_length(resultObj) != mesh->GetVertexCount())
- {
- LOG(Error, "Invalid buffer size.");
- return true;
- }
+ return nullptr;
}
MeshBufferType bufferType;
@@ -859,35 +779,96 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
bufferType = MeshBufferType::Index;
break;
default:
- return true;
+ return nullptr;
}
BytesContainer data;
+ int32 dataCount;
if (forceGpu)
{
// Get data from GPU
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
if (task == nullptr)
- return true;
+ return nullptr;
task->Start();
model->Locker.Unlock();
if (task->Wait())
{
LOG(Error, "Task failed.");
- return true;
+ return nullptr;
}
model->Locker.Lock();
+
+ // Extract elements count from result data
+ switch (bufferType)
+ {
+ case MeshBufferType::Index:
+ dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32));
+ break;
+ case MeshBufferType::Vertex0:
+ dataCount = data.Length() / sizeof(VB0ElementType);
+ break;
+ case MeshBufferType::Vertex1:
+ dataCount = data.Length() / sizeof(VB1ElementType);
+ break;
+ case MeshBufferType::Vertex2:
+ dataCount = data.Length() / sizeof(VB2ElementType);
+ break;
+ }
}
else
{
// Get data from CPU
- int32 count;
- if (DownloadDataCPU(bufferType, data, count))
- return true;
+ if (DownloadDataCPU(bufferType, data, dataCount))
+ return nullptr;
}
- ConvertMeshData(mesh, type, resultObj, data.Get());
- return false;
+ // Convert into managed array
+ MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
+ void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
+ const int32 elementSize = data.Length() / dataCount;
+ switch (type)
+ {
+ case InternalBufferType::VB0:
+ case InternalBufferType::VB1:
+ case InternalBufferType::VB2:
+ {
+ Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
+ break;
+ }
+ case InternalBufferType::IB16:
+ {
+ if (elementSize == sizeof(uint16))
+ {
+ Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
+ }
+ else
+ {
+ auto dst = (uint16*)managedArrayPtr;
+ auto src = (uint32*)data.Get();
+ for (int32 i = 0; i < dataCount; i++)
+ dst[i] = src[i];
+ }
+ break;
+ }
+ case InternalBufferType::IB32:
+ {
+ if (elementSize == sizeof(uint16))
+ {
+ auto dst = (uint32*)managedArrayPtr;
+ auto src = (uint16*)data.Get();
+ for (int32 i = 0; i < dataCount; i++)
+ dst[i] = src[i];
+ }
+ else
+ {
+ Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
+ }
+ break;
+ }
+ }
+
+ return result;
}
#endif
diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h
index ee16c16e3..9b1ab4846 100644
--- a/Source/Engine/Graphics/Models/Mesh.h
+++ b/Source/Engine/Graphics/Models/Mesh.h
@@ -321,6 +321,6 @@ private:
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 UpdateTrianglesUInt(int32 triangleCount, MonoArray* trianglesObj);
API_FUNCTION(NoProxy) bool UpdateTrianglesUShort(int32 triangleCount, MonoArray* trianglesObj);
- API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
+ API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
#endif
};
diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp
index 89db8ff8b..f33b8b4fd 100644
--- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp
+++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp
@@ -516,64 +516,12 @@ enum class InternalBufferType
IB32 = 4,
};
-void ConvertMeshData(SkinnedMesh* mesh, InternalBufferType type, MonoArray* resultObj, void* srcData)
-{
- auto vertices = mesh->GetVertexCount();
- auto triangles = mesh->GetTriangleCount();
- auto indices = triangles * 3;
- auto use16BitIndexBuffer = mesh->Use16BitIndexBuffer();
-
- void* managedArrayPtr = mono_array_addr_with_size(resultObj, 0, 0);
- switch (type)
- {
- case InternalBufferType::VB0:
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(VB0SkinnedElementType) * vertices);
- break;
- }
- case InternalBufferType::IB16:
- {
- if (use16BitIndexBuffer)
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint16) * indices);
- }
- else
- {
- auto dst = (uint16*)managedArrayPtr;
- auto src = (uint32*)srcData;
- for (int32 i = 0; i < indices; i++)
- {
- dst[i] = src[i];
- }
- }
- break;
- }
- case InternalBufferType::IB32:
- {
- if (use16BitIndexBuffer)
- {
- auto dst = (uint32*)managedArrayPtr;
- auto src = (uint16*)srcData;
- for (int32 i = 0; i < indices; i++)
- {
- dst[i] = src[i];
- }
- }
- else
- {
- Platform::MemoryCopy(managedArrayPtr, srcData, sizeof(uint32) * indices);
- }
- break;
- }
- }
-}
-
-bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
+MonoArray* SkinnedMesh::DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI)
{
SkinnedMesh* mesh = this;
InternalBufferType type = (InternalBufferType)typeI;
auto model = mesh->GetSkinnedModel();
- ASSERT(model && resultObj);
+ ScopeLock lock(model->Locker);
// Virtual assets always fetch from GPU memory
forceGpu |= model->IsVirtual();
@@ -581,23 +529,7 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
if (!mesh->IsInitialized() && forceGpu)
{
LOG(Error, "Cannot load mesh data from GPU if it's not loaded.");
- return true;
- }
- if (type == InternalBufferType::IB16 || type == InternalBufferType::IB32)
- {
- if (mono_array_length(resultObj) != mesh->GetTriangleCount() * 3)
- {
- LOG(Error, "Invalid buffer size.");
- return true;
- }
- }
- else
- {
- if (mono_array_length(resultObj) != mesh->GetVertexCount())
- {
- LOG(Error, "Invalid buffer size.");
- return true;
- }
+ return nullptr;
}
MeshBufferType bufferType;
@@ -610,37 +542,89 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
case InternalBufferType::IB32:
bufferType = MeshBufferType::Index;
break;
- default: CRASH;
- return true;
+ default:
+ return nullptr;
}
BytesContainer data;
+ int32 dataCount;
if (forceGpu)
{
// Get data from GPU
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
if (task == nullptr)
- return true;
+ return nullptr;
task->Start();
model->Locker.Unlock();
if (task->Wait())
{
LOG(Error, "Task failed.");
- return true;
+ return nullptr;
}
model->Locker.Lock();
+
+ // Extract elements count from result data
+ switch (bufferType)
+ {
+ case MeshBufferType::Index:
+ dataCount = data.Length() / (Use16BitIndexBuffer() ? sizeof(uint16) : sizeof(uint32));
+ break;
+ case MeshBufferType::Vertex0:
+ dataCount = data.Length() / sizeof(VB0SkinnedElementType);
+ break;
+ }
}
else
{
// Get data from CPU
- int32 count;
- if (DownloadDataCPU(bufferType, data, count))
- return true;
+ if (DownloadDataCPU(bufferType, data, dataCount))
+ return nullptr;
}
- // Convert into managed memory
- ConvertMeshData(mesh, type, resultObj, data.Get());
- return false;
+ // Convert into managed array
+ MonoArray* result = mono_array_new(mono_domain_get(), mono_type_get_class(mono_reflection_type_get_type(resultType)), dataCount);
+ void* managedArrayPtr = mono_array_addr_with_size(result, 0, 0);
+ const int32 elementSize = data.Length() / dataCount;
+ switch (type)
+ {
+ case InternalBufferType::VB0:
+ {
+ Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
+ break;
+ }
+ case InternalBufferType::IB16:
+ {
+ if (elementSize == sizeof(uint16))
+ {
+ Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
+ }
+ else
+ {
+ auto dst = (uint16*)managedArrayPtr;
+ auto src = (uint32*)data.Get();
+ for (int32 i = 0; i < dataCount; i++)
+ dst[i] = src[i];
+ }
+ break;
+ }
+ case InternalBufferType::IB32:
+ {
+ if (elementSize == sizeof(uint16))
+ {
+ auto dst = (uint32*)managedArrayPtr;
+ auto src = (uint16*)data.Get();
+ for (int32 i = 0; i < dataCount; i++)
+ dst[i] = src[i];
+ }
+ else
+ {
+ Platform::MemoryCopy(managedArrayPtr, data.Get(), data.Length());
+ }
+ break;
+ }
+ }
+
+ return result;
}
#endif
diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.h b/Source/Engine/Graphics/Models/SkinnedMesh.h
index 8bf957554..57a382cff 100644
--- a/Source/Engine/Graphics/Models/SkinnedMesh.h
+++ b/Source/Engine/Graphics/Models/SkinnedMesh.h
@@ -199,6 +199,6 @@ private:
#if !COMPILE_WITHOUT_CSHARP
API_FUNCTION(NoProxy) bool UpdateMeshUInt(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
API_FUNCTION(NoProxy) bool UpdateMeshUShort(MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* blendIndicesObj, MonoArray* blendWeightsObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj);
- API_FUNCTION(NoProxy) bool DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI);
+ API_FUNCTION(NoProxy) MonoArray* DownloadBuffer(bool forceGpu, MonoReflectionType* resultType, int32 typeI);
#endif
};
diff --git a/Source/Engine/Graphics/SkinnedMesh.cs b/Source/Engine/Graphics/SkinnedMesh.cs
index 5998c6a1e..8fb7a83dc 100644
--- a/Source/Engine/Graphics/SkinnedMesh.cs
+++ b/Source/Engine/Graphics/SkinnedMesh.cs
@@ -274,9 +274,8 @@ namespace FlaxEngine
/// The gathered data.
public Vertex0[] DownloadVertexBuffer0(bool forceGpu = false)
{
- var vertices = VertexCount;
- var result = new Vertex0[vertices];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0))
+ var result = (Vertex0[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(Vertex0), (int)InternalBufferType.VB0);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -292,7 +291,7 @@ namespace FlaxEngine
var vb0 = DownloadVertexBuffer0(forceGpu);
- var vertices = VertexCount;
+ var vertices = vb0.Length;
var result = new Vertex[vertices];
for (int i = 0; i < vertices; i++)
{
@@ -319,9 +318,8 @@ namespace FlaxEngine
/// The gathered data.
public uint[] DownloadIndexBuffer(bool forceGpu = false)
{
- var triangles = TriangleCount;
- var result = new uint[triangles * 3];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32))
+ var result = (uint[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(uint), (int)InternalBufferType.IB32);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}
@@ -334,9 +332,8 @@ namespace FlaxEngine
/// The gathered data.
public ushort[] DownloadIndexBufferUShort(bool forceGpu = false)
{
- var triangles = TriangleCount;
- var result = new ushort[triangles * 3];
- if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16))
+ var result = (ushort[])Internal_DownloadBuffer(__unmanagedPtr, forceGpu, typeof(ushort), (int)InternalBufferType.IB16);
+ if (result == null)
throw new Exception("Failed to download mesh data.");
return result;
}