namespace vke.glTF {
using static Vulkan.Utils;
using static vke.Model;
+ using System.Runtime.CompilerServices;
/// <summary>
/// Loading context with I as the vertex index type (uint16,uint32)
public GL.Gltf gltf;
public string baseDirectory;
- public byte[][] loadedBuffers;
- public GCHandle[] bufferHandles;
+ public Memory<byte>[] loadedBuffers;
List<Mesh> meshes;
string path;
cmdPool = _cmdPool;
baseDirectory = Path.GetDirectoryName (path);
gltf = Interface.LoadModel (path);
- loadedBuffers = new byte [gltf.Buffers.Length] [];
- bufferHandles = new GCHandle [gltf.Buffers.Length];
+ loadedBuffers = new Memory<byte> [gltf.Buffers.Length];
}
static byte[] loadDataUri (GL.Image img) {
}
void ensureBufferIsLoaded (int bufferIdx) {
- if (loadedBuffers[bufferIdx] == null) {
+ if (loadedBuffers[bufferIdx].IsEmpty) {
//load full buffer
string uri = gltf.Buffers[bufferIdx].Uri;
if (string.IsNullOrEmpty(uri))//glb
loadedBuffers[bufferIdx] = loadDataUri (gltf.Buffers[bufferIdx]);//TODO:check this func=>System.Buffers.Text.Base64.EncodeToUtf8InPlace
else
loadedBuffers[bufferIdx] = File.ReadAllBytes (Path.Combine (baseDirectory, gltf.Buffers[bufferIdx].Uri));
- bufferHandles[bufferIdx] = GCHandle.Alloc (loadedBuffers[bufferIdx], GCHandleType.Pinned);
}
}
stagging.Map ();
unsafe {
- byte* stagVertPtrInit = (byte*)stagging.MappedData.ToPointer ();
- byte* stagIdxPtrInit = (byte*)(stagging.MappedData.ToPointer ()) + vertSize;
- byte* stagVertPtr = stagVertPtrInit;
- byte* stagIdxPtr = stagIdxPtrInit;
+
+ Span<byte> stagVertPtrInit = new Span<byte>(stagging.MappedData.ToPointer (), (int)vertSize);
+ Span<byte> stagIdxPtrInit = new Span<byte>((byte*)stagging.MappedData.ToPointer() + vertSize, (int)idxSize);
+ Span<byte> stagVertPtr = stagVertPtrInit, stagIdxPtr = stagIdxPtrInit;
foreach (GL.Mesh mesh in gltf.Meshes) {
prim.bb.isValid = true;
//Interleaving vertices
- byte * inPosPtr = null, inNormPtr = null, inUvPtr = null, inUv1Ptr = null;
+ Span<byte> inPosPtr = Span<byte>.Empty, inNormPtr = Span<byte>.Empty, inUvPtr = Span<byte>.Empty, inUv1Ptr = Span<byte>.Empty;
GL.BufferView bv = gltf.BufferViews[(int)AccPos.BufferView];
- inPosPtr = (byte*)bufferHandles[bv.Buffer].AddrOfPinnedObject ().ToPointer ();
- inPosPtr += AccPos.ByteOffset + bv.ByteOffset;
+ inPosPtr = loadedBuffers[bv.Buffer].Span.Slice (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;
+ inNormPtr = loadedBuffers[bv.Buffer].Span.Slice (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;
+ inUvPtr = loadedBuffers[bv.Buffer].Span.Slice (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;
+ inUv1Ptr = loadedBuffers[bv.Buffer].Span.Slice (AccUv1.ByteOffset + bv.ByteOffset);
}
//TODO: use vertex attributes scan for copying data if they exists
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;
+ inPosPtr.Slice (0, 12).CopyTo (stagVertPtr);
+ inPosPtr = inPosPtr.Slice(12);
+ if (!inNormPtr.IsEmpty) {
+ inNormPtr.Slice (0, 12).CopyTo (stagVertPtr.Slice (12));
+ inNormPtr = inNormPtr.Slice (12);
}
if (inUvPtr != null) {
- System.Buffer.MemoryCopy (inUvPtr, stagVertPtr + 24, 8, 8);
- inUvPtr += 8;
+ inUvPtr.Slice (0, 8).CopyTo (stagVertPtr.Slice (24));
+ inUvPtr = inUvPtr.Slice (8);
}
if (inUv1Ptr != null) {
- System.Buffer.MemoryCopy (inUv1Ptr, stagVertPtr + 32, 8, 8);
- inUv1Ptr += 8;
+ inUv1Ptr.Slice (0, 8).CopyTo (stagVertPtr.Slice (32));
+ inUv1Ptr = inUvPtr.Slice (8);
}
- stagVertPtr += vertexByteSize;
+ stagVertPtr = stagVertPtr.Slice (vertexByteSize);
}
+ /*Span<byte> s = stagVertPtrInit;
+ for (int i = 0; i < s.Length; i++)
+ Console.Write (s[i].ToString ("X2") + (i % 32 == 0 ? "\n" : " "));*/
+
+
//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;
+ Span<byte> inIdxPtr = loadedBuffers[bv.Buffer].Span.Slice (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;
+ inIdxPtr.Slice (0, acc.Count * 2).CopyTo (stagIdxPtr);
+ stagIdxPtr = stagIdxPtr.Slice (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;
+
+ Span<uint> usPtr = MemoryMarshal.Cast<byte, uint> (stagIdxPtr);
+ Span<ushort> inPtr = MemoryMarshal.Cast < byte, ushort> (inIdxPtr);
+ for (int i = 0; i < acc.Count; i++)
+ usPtr[i] = inPtr[i];
+ stagIdxPtr = stagIdxPtr.Slice (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;
+ inIdxPtr.Slice (0, acc.Count * 4).CopyTo (stagIdxPtr);
+ stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4);
} else {
- ushort* usPtr = (ushort*)stagIdxPtr;
- uint* inPtr = (uint*)inIdxPtr;
+ Span<ushort> usPtr = MemoryMarshal.Cast<byte, ushort> (stagIdxPtr);
+ Span<uint> inPtr = MemoryMarshal.Cast<byte, uint> (inIdxPtr);
+
for (int i = 0; i < acc.Count; i++)
usPtr[i] = (ushort)inPtr[i];
- stagIdxPtr += (long)acc.Count * 2;
+ stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2);
}
} else if (acc.ComponentType == GL.Accessor.ComponentTypeEnum.UNSIGNED_BYTE) {
//convert
if (indexType == VkIndexType.Uint16) {
- ushort* usPtr = (ushort*)stagIdxPtr;
+ Span<ushort> usPtr = MemoryMarshal.Cast<byte, ushort> (stagIdxPtr);
for (int i = 0; i < acc.Count; i++)
usPtr[i] = (ushort)inIdxPtr[i];
- stagIdxPtr += (long)acc.Count * 2;
+ stagIdxPtr = stagIdxPtr.Slice (acc.Count * 2);
} else {
- uint* usPtr = (uint*)stagIdxPtr;
+ Span<uint> usPtr = MemoryMarshal.Cast<byte, uint> (stagIdxPtr);
for (int i = 0; i < acc.Count; i++)
usPtr[i] = (uint)inIdxPtr[i];
- stagIdxPtr += (long)acc.Count * 4;
+ stagIdxPtr = stagIdxPtr.Slice (acc.Count * 4);
}
} else
throw new NotImplementedException ();
}
meshes.Add (m);
}
+
+ /*ReadOnlySpan<byte> tmp = new ReadOnlySpan<byte> (stagging.MappedData.ToPointer (), (int)size);
+ Memory<byte> mtmp = new Memory<byte> (tmp.ToArray());
+ mtmp.Dump();*/
}
stagging.Unmap ();
if (img.BufferView != null) {//load image from gltf buffer view
GL.BufferView bv = gltf.BufferViews[(int)img.BufferView];
ensureBufferIsLoaded (bv.Buffer);
- vkimg = Image.Load (dev, bufferHandles[bv.Buffer].AddrOfPinnedObject () + bv.ByteOffset, (ulong)bv.ByteLength, VkImageUsageFlags.TransferSrc);
+ vkimg = Image.Load (dev, loadedBuffers[bv.Buffer].Slice (bv.ByteOffset), (ulong)bv.ByteLength, VkImageUsageFlags.TransferSrc);
} else if (img.Uri.StartsWith ("data:", StringComparison.Ordinal)) {//load base64 encoded image
Debug.WriteLine ("loading embedded image {0} : {1}", img.Name, img.MimeType);
vkimg = Image.Load (dev, glTFLoader.loadDataUri (img), VkImageUsageFlags.TransferSrc);
if (img.BufferView != null) {//load image from gltf buffer view
GL.BufferView bv = gltf.BufferViews[(int)img.BufferView];
ensureBufferIsLoaded (bv.Buffer);
- if (Image.USE_STB_SHARP)
- vkimg = Image.Load (dev, transferQ, cmdPool, loadedBuffers[bv.Buffer].Skip(bv.ByteOffset).Take(bv.ByteLength).ToArray());
- else
- vkimg = Image.Load (dev, transferQ, cmdPool, bufferHandles[bv.Buffer].AddrOfPinnedObject () + bv.ByteOffset, (ulong)bv.ByteLength);
-
+ vkimg = Image.Load (dev, transferQ, cmdPool, loadedBuffers[bv.Buffer].Slice (bv.ByteOffset, bv.ByteLength));
} else if (img.Uri.StartsWith ("data:", StringComparison.Ordinal)) {//load base64 encoded image
Debug.WriteLine ("loading embedded image {0} : {1}", img.Name, img.MimeType);
vkimg = Image.Load (dev, transferQ, cmdPool, glTFLoader.loadDataUri (img));
}
for (int i = 0; i < gltf.Buffers.Length; i++) {
- if (bufferHandles[i].IsAllocated)
- bufferHandles[i].Free ();
+ //if (bufferHandles[i].IsAllocated)
+ //bufferHandles[i].Free ();
}
isDisposed = true;
static extern IntPtr Load ([MarshalAs (UnmanagedType.LPStr)] string filename, out int x, out int y, out int channels_in_file, int desired_channels);
[DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_memory")]
- static extern IntPtr Load (IntPtr bitmap, int byteCount, out int x, out int y, out int channels_in_file, int desired_channels);
+ static extern IntPtr Load (IntPtr bitmap, int byteCount, out int x, out int y, out int channels_in_file, int desired_channels);
- [DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_image_free")]
+ [DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_memory")]
+ static extern IntPtr Load2 (ref byte bitmap, int byteCount, out int x, out int y, out int channels_in_file, int desired_channels);
+
+ [DllImport (stblib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_image_free")]
static extern void FreeImage (IntPtr img);
public readonly IntPtr Handle;
Channels = requestedChannels;
}
/// <summary>
+ /// Open image with STBI library
+ /// </summary>
+ /// <param name="bitmap">raw bitmap datas</param>
+ /// <param name="requestedChannels">Force returned channels count, set 0 for original count</param>
+ public StbImage (Memory<byte> bitmap, int requestedChannels = 4) {
+ Handle = StbImage.Load2 (ref MemoryMarshal.GetReference(bitmap.Span), bitmap.Length, out Width, out Height, out Channels, requestedChannels);
+ if (Handle == IntPtr.Zero)
+ throw new Exception ($"STBI image loading error.");
+ if (requestedChannels > 0)
+ Channels = requestedChannels;
+ }
+ /// <summary>
/// copy pixels to destination.
/// </summary>
/// <param name="destPtr">Destination pointer.</param>
//
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
using System;
+using System.Buffers;
using System.Diagnostics;
using Vulkan;
return false;*/
return true;
}
+ /// <summary>
+ /// Load image from byte array containing full image file (jpg, png,...)
+ /// </summary>
+ public static Image Load (Device dev, Queue staggingQ, CommandPool staggingCmdPool,
+ Memory<byte> bitmap, VkFormat format = VkFormat.Undefined,
+ VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.DeviceLocal,
+ VkImageTiling tiling = VkImageTiling.Optimal, bool generateMipmaps = true,
+ VkImageType imageType = VkImageType.Image2D,
+ VkImageUsageFlags usage = VkImageUsageFlags.Sampled | VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst) {
+
+ if (format == VkFormat.Undefined)
+ format = DefaultTextureFormat;
+ if (tiling == VkImageTiling.Optimal)
+ usage |= VkImageUsageFlags.TransferDst;
+ if (generateMipmaps)
+ usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst);
+ /*#if STB_SHARP
+ StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromMemory (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
+ uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1;
+ image = new byte [stbi.Data.Length];
+ //rgba to argb for cairo.
+ for (int i = 0; i < stbi.Data.Length; i += 4) {
+ image [i] = stbi.Data[i + 2];
+ image [i + 1] = stbi.Data [i + 1];
+ image [i + 2] = stbi.Data [i];
+ image [i + 3] = stbi.Data [i + 3];
+ }
+ Dimensions = new Size (stbi.Width, stbi.Height);
+ #else*/
+
+ using (StbImage stbi = new StbImage (bitmap)) {
+ uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1;
+
+ Image img = new Image (dev, format, usage, memoryProps, (uint)stbi.Width, (uint)stbi.Height, imageType,
+ VkSampleCountFlags.SampleCount1, tiling, mipLevels);
+
+ img.load (staggingQ, staggingCmdPool, stbi.Handle, generateMipmaps);
+
+ return img;
+ }
+//#endif
+ }
+ /// <summary>
+ /// create host visible linear image without command from data pointed by IntPtr pointer containing full image file (jpg, png,...)
+ /// </summary>
+ public static Image Load (Device dev,
+ Memory<byte> bitmap, ulong bitmapByteCount, VkImageUsageFlags usage = VkImageUsageFlags.TransferSrc,
+ VkFormat format = VkFormat.Undefined,
+ VkMemoryPropertyFlags memoryProps = VkMemoryPropertyFlags.HostVisible | VkMemoryPropertyFlags.HostCoherent,
+ VkImageTiling tiling = VkImageTiling.Linear, bool generateMipmaps = false,
+ VkImageType imageType = VkImageType.Image2D) {
+
+ if (format == VkFormat.Undefined)
+ format = DefaultTextureFormat;
+ if (generateMipmaps)
+ usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst);
+
+ using (StbImage stbi = new StbImage (bitmap)) {
+ uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1;
+
+ Image img = new Image (dev, format, usage, memoryProps, (uint)stbi.Width, (uint)stbi.Height, imageType,
+ VkSampleCountFlags.SampleCount1, tiling, mipLevels);
+
+ img.Map ();
+ stbi.CoptyTo (img.MappedData);
+ img.Unmap ();
+
+ return img;
+ }
+ }
+
/// <summary>
/// Load image from byte array containing full image file (jpg, png,...)
/// </summary>
usage |= VkImageUsageFlags.TransferDst;
if (generateMipmaps)
usage |= (VkImageUsageFlags.TransferSrc | VkImageUsageFlags.TransferDst);
-#if STB_SHARP
-
+/*#if STB_SHARP
StbImageSharp.ImageResult stbi = StbImageSharp.ImageResult.FromMemory (stream, StbImageSharp.ColorComponents.RedGreenBlueAlpha);
uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1;
image = new byte [stbi.Data.Length];
image [i + 3] = stbi.Data [i + 3];
}
Dimensions = new Size (stbi.Width, stbi.Height);
-#else
+#else*/
using (StbImage stbi = new StbImage (bitmap, bitmapByteCount)) {
uint mipLevels = generateMipmaps ? ComputeMipLevels (stbi.Width, stbi.Height) : 1;
return img;
}
-#endif
+//#endif
}
/// <summary>