public static extern bool crnd_get_texture_info(IntPtr data, uint data_size, [In, Out] crn_texture_info info);
public static unsafe bool Decompress(byte[] rawData, List <List <Memory <byte> > > data, out crn_texture_info info, Action <crn_texture_info> onInfoDecoded = null) { fixed(byte *pData = rawData) { info = new crn_texture_info(); if (!NativeMethods.crnd_get_texture_info(new IntPtr(pData), (uint)rawData.Length, info)) { return(false); } onInfoDecoded?.Invoke(info); bool allocateData = data.Count == 0; if (!allocateData) { if (data.Count != info.faces) { return(false); } foreach (var face in data) { if (face.Count != info.levels) { return(false); } } } else { for (int f = 0; f < info.faces; f++) { data.Add(new List <Memory <byte> >()); } } var pointers = new IntPtr[Constants.MAX_FACES]; var handles = new List <MemoryHandle>(); IntPtr context = IntPtr.Zero; var dataHandle = rawData.AsMemory().Pin(); try { context = NativeMethods.crnd_unpack_begin(new IntPtr(dataHandle.Pointer), (uint)rawData.Length); for (int m = 0; m < info.levels; m++) { uint width = Math.Max(1, info.width >> m); uint height = Math.Max(1, info.height >> m); uint blocks_x = Math.Max(1, (width + 3) >> 2); uint blocks_y = Math.Max(1, (height + 3) >> 2); uint row_pitch = blocks_x * info.bytes_per_block; uint face_size = row_pitch * blocks_y; try { for (int f = 0; f < info.faces; f++) { if (allocateData) { var face_data = new byte[face_size]; data[f].Add(face_data.AsMemory()); } var handle = data[f][m].Pin(); handles.Add(handle); pointers[f] = new IntPtr(handle.Pointer); } fixed(void *p = pointers) { var unpacked = NativeMethods.crnd_unpack_level(context, new IntPtr(p), face_size, row_pitch, (uint)m); if (!unpacked) { return(false); } } } finally { foreach (var h in handles) { h.Dispose(); } handles.Clear(); } } } finally { if (context != IntPtr.Zero) { NativeMethods.crnd_unpack_end(context); } dataHandle.Dispose(); } return(true); } }