public static extern bool crnd_get_texture_info(IntPtr data, uint data_size, [In, Out] crn_texture_info info);
Beispiel #2
0
        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);
            }
        }