protected override void Dispose(bool disposing) { if (disposing) { Vertices.Unmap(); Vertices.Dispose(); } base.Dispose(disposing); }
//TODO: some buffer data are reused between primitives, and I duplicate the datas //buffers must be constructed without duplications public Mesh[] LoadMeshes <TVertex> (VkIndexType indexType, Buffer vbo, ulong vboOffset, Buffer ibo, ulong iboOffset) { ulong vCount, iCount; VkIndexType idxType; GetVertexCount(out vCount, out iCount, out idxType); int vertexByteSize = Marshal.SizeOf <TVertex> (); ulong vertSize = vCount * (ulong)vertexByteSize; ulong idxSize = iCount * (indexType == VkIndexType.Uint16 ? 2ul : 4ul); ulong size = vertSize + idxSize; int vertexCount = 0, indexCount = 0; int autoNamedMesh = 1; meshes = new List <Mesh> (); using (HostBuffer stagging = new HostBuffer(dev, VkBufferUsageFlags.TransferSrc, size)) { stagging.Map(); unsafe { byte *stagVertPtrInit = (byte *)stagging.MappedData.ToPointer(); byte *stagIdxPtrInit = (byte *)(stagging.MappedData.ToPointer()) + vertSize; byte *stagVertPtr = stagVertPtrInit; byte *stagIdxPtr = stagIdxPtrInit; foreach (GL.Mesh mesh in gltf.Meshes) { string meshName = mesh.Name; if (string.IsNullOrEmpty(meshName)) { meshName = "mesh_" + autoNamedMesh.ToString(); autoNamedMesh++; } Mesh m = new Mesh { Name = meshName }; foreach (GL.MeshPrimitive p in mesh.Primitives) { GL.Accessor AccPos = null, AccNorm = null, AccUv = null, AccUv1 = null; int accessorIdx; if (p.Attributes.TryGetValue("POSITION", out accessorIdx)) { AccPos = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccPos.BufferView].Buffer); } if (p.Attributes.TryGetValue("NORMAL", out accessorIdx)) { AccNorm = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccNorm.BufferView].Buffer); } if (p.Attributes.TryGetValue("TEXCOORD_0", out accessorIdx)) { AccUv = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccUv.BufferView].Buffer); } if (p.Attributes.TryGetValue("TEXCOORD_1", out accessorIdx)) { AccUv1 = gltf.Accessors[accessorIdx]; EnsureBufferIsLoaded(gltf.BufferViews[(int)AccUv1.BufferView].Buffer); } Primitive prim = new Primitive { indexBase = (uint)indexCount, vertexBase = vertexCount, vertexCount = (uint)AccPos.Count, material = (uint)(p.Material ?? 0) }; prim.bb.min.ImportFloatArray(AccPos.Min); prim.bb.max.ImportFloatArray(AccPos.Max); prim.bb.isValid = true; //Interleaving vertices byte *inPosPtr = null, inNormPtr = null, inUvPtr = null, inUv1Ptr = null; GL.BufferView bv = gltf.BufferViews[(int)AccPos.BufferView]; inPosPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inPosPtr += AccPos.ByteOffset + bv.ByteOffset; if (AccNorm != null) { bv = gltf.BufferViews[(int)AccNorm.BufferView]; inNormPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inNormPtr += AccNorm.ByteOffset + bv.ByteOffset; } if (AccUv != null) { bv = gltf.BufferViews[(int)AccUv.BufferView]; inUvPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inUvPtr += AccUv.ByteOffset + bv.ByteOffset; } if (AccUv1 != null) { bv = gltf.BufferViews[(int)AccUv1.BufferView]; inUv1Ptr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inUv1Ptr += AccUv1.ByteOffset + bv.ByteOffset; } for (int j = 0; j < prim.vertexCount; j++) { System.Buffer.MemoryCopy(inPosPtr, stagVertPtr, 12, 12); inPosPtr += 12; if (inNormPtr != null) { System.Buffer.MemoryCopy(inNormPtr, stagVertPtr + 12, 12, 12); inNormPtr += 12; } if (inUvPtr != null) { System.Buffer.MemoryCopy(inUvPtr, stagVertPtr + 24, 8, 8); inUvPtr += 8; } if (inUv1Ptr != null) { System.Buffer.MemoryCopy(inUv1Ptr, stagVertPtr + 32, 8, 8); inUv1Ptr += 8; } stagVertPtr += vertexByteSize; } //indices loading if (p.Indices != null) { GL.Accessor acc = gltf.Accessors[(int)p.Indices]; bv = gltf.BufferViews[(int)acc.BufferView]; byte *inIdxPtr = (byte *)bufferHandles[bv.Buffer].AddrOfPinnedObject().ToPointer(); inIdxPtr += acc.ByteOffset + bv.ByteOffset; //TODO:double check this, I dont seems to increment stag pointer if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_SHORT) { if (indexType == VkIndexType.Uint16) { System.Buffer.MemoryCopy(inIdxPtr, stagIdxPtr, (long)acc.Count * 2, (long)acc.Count * 2); stagIdxPtr += (long)acc.Count * 2; } else { uint * usPtr = (uint *)stagIdxPtr; ushort *inPtr = (ushort *)inIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = inPtr[i]; } stagIdxPtr += (long)acc.Count * 4; } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_INT) { if (indexType == VkIndexType.Uint32) { System.Buffer.MemoryCopy(inIdxPtr, stagIdxPtr, (long)acc.Count * 4, (long)acc.Count * 4); stagIdxPtr += (long)acc.Count * 4; } else { ushort *usPtr = (ushort *)stagIdxPtr; uint * inPtr = (uint *)inIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = (ushort)inPtr[i]; } stagIdxPtr += (long)acc.Count * 2; } } else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_BYTE) { //convert if (indexType == VkIndexType.Uint16) { ushort *usPtr = (ushort *)stagIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = (ushort)inIdxPtr[i]; } stagIdxPtr += (long)acc.Count * 2; } else { uint *usPtr = (uint *)stagIdxPtr; for (int i = 0; i < acc.Count; i++) { usPtr[i] = (uint)inIdxPtr[i]; } stagIdxPtr += (long)acc.Count * 4; } } else { throw new NotImplementedException(); } prim.indexCount = (uint)acc.Count; indexCount += acc.Count; } m.AddPrimitive(prim); vertexCount += AccPos.Count; } meshes.Add(m); } } stagging.Unmap(); CommandBuffer cmd = cmdPool.AllocateCommandBuffer(); cmd.Start(VkCommandBufferUsageFlags.OneTimeSubmit); stagging.CopyTo(cmd, vbo, vertSize, 0, vboOffset); if (iCount > 0) { stagging.CopyTo(cmd, ibo, idxSize, vertSize, iboOffset); } cmd.End(); transferQ.Submit(cmd); dev.WaitIdle(); cmd.Free(); } return(meshes.ToArray()); }