Exemplo n.º 1
0
        public static unsafe byte[] DecompressImage(int width, int height, byte[] blocks, SquishFlags flags, Action <int, int> progressFn)
        {
            //
            // fix any bad flags
            //
            flags = fixFlags(flags);
            //
            // initialise the block input
            //
            byte[] dest = new byte[width * height * 4];

            int bytesPerBlock = (flags & SquishFlags.Dxt1) != 0 ? 8 : 16;

            int progress = 0;

            progressFn?.Invoke(0, height);
            //
            // loop over blocks
            //
            fixed(byte *pBlocks = blocks)
            {
                byte *source = pBlocks;

                fixed(byte *pDest = dest)
                {
                    byte *rgba = pDest;

                    Parallel.ForEach(SteppedEnumerable.SteppedRange(0, height, 4), y =>
                    {
                        Parallel.ForEach(SteppedEnumerable.SteppedRange(0, width, 4), x =>
                        {
                            //
                            // decompress the block
                            //
                            int blockNum = (width + 3) / 4 * (y / 4) + x / 4;

                            byte *sourceBlock = source + bytesPerBlock * blockNum;

                            byte[] targetRgba = new byte[4 * 16];
                            //
                            // write the decompressed pixels to the correct image locations
                            //
                            fixed(byte *pTargetRgba = targetRgba)
                            {
                                decompress(pTargetRgba, sourceBlock, flags);

                                byte *sourcePixel = pTargetRgba;

                                for (int py = 0; py < 4; ++py)
                                {
                                    for (int px = 0; px < 4; ++px)
                                    {
                                        //
                                        // get the target location
                                        //
                                        int sx = x + px;
                                        int sy = y + py;

                                        if (sx < width && sy < height)
                                        {
                                            byte *targetPixel = rgba + 4 * (width * sy + sx);
                                            //
                                            // copy the rgba value
                                            //
                                            for (int i = 0; i < 4; ++i)
                                            {
                                                *targetPixel++ = *sourcePixel++;
                                            }
                                        }
                                        else
                                        {
                                            //
                                            // skip this pixel as it is outside the image
                                            //
                                            sourcePixel += 4;
                                        }
                                    }
                                }
                            }

                            Interlocked.Add(ref progress, 4);

                            progressFn?.Invoke(progress, height);
                        });
                    });
                }
            }

            progressFn?.Invoke(height, height);

            return(dest);
        }
Exemplo n.º 2
0
        public static unsafe byte[] CompressImage(byte[] rgba, int width, int height, SquishFlags flags, Action <int, int> progressFn)
        {
            //
            // fix any bad flags
            //
            flags = fixFlags(flags);
            //
            // initialise the block output
            //
            int blockCount = (width + 3) / 4 * ((height + 3) / 4);

            int blockSize = (flags & SquishFlags.Dxt1) != 0 ? 8 : 16;

            byte[] blocks = new byte[blockCount * blockSize];

            int progress = 0;

            progressFn?.Invoke(0, height);
            //
            // loop over blocks
            //
            fixed(byte *pBlocks = blocks)
            {
                byte *targetBlock = pBlocks;

                fixed(byte *pRgba = rgba)
                {
                    byte *source = pRgba;

                    Parallel.ForEach(SteppedEnumerable.SteppedRange(0, height, 4), y =>
                    {
                        Parallel.ForEach(SteppedEnumerable.SteppedRange(0, width, 4), x =>
                        {
                            //
                            // build the 4x4 block of pixels
                            //
                            byte[] sourceRgba = new byte[16 * 4];

                            int mask = 0;

                            fixed(byte *pSourceRgba = sourceRgba)
                            {
                                byte *targetPixel = pSourceRgba;

                                for (int py = 0; py < 4; ++py)
                                {
                                    for (int px = 0; px < 4; ++px)
                                    {
                                        //
                                        // get the source pixel in the image
                                        //
                                        int sx = x + px;
                                        int sy = y + py;
                                        //
                                        // enable if we're in the image
                                        //
                                        if (sx < width && sy < height)
                                        {
                                            //
                                            // copy the rgba value
                                            //
                                            byte *sourcePixel = source + 4 * (width * sy + sx);

                                            for (int i = 0; i < 4; ++i)
                                            {
                                                *targetPixel++ = *sourcePixel++;
                                            }
                                            //
                                            // enable this pixel
                                            //
                                            mask |= 1 << (4 * py + px);
                                        }
                                        else
                                        {
                                            //
                                            // skip this pixel as its outside the image
                                            //
                                            targetPixel += 4;
                                        }
                                    }
                                }
                                //
                                // compress it into the output
                                //
                                int blockNum = (width + 3) / 4 * (y / 4) + x / 4;

                                byte *outputBlock = targetBlock + blockSize * blockNum;

                                compressMasked(pSourceRgba, mask, outputBlock, flags);
                            }
                        });

                        Interlocked.Add(ref progress, 4);

                        progressFn?.Invoke(progress, height);
                    });
                }
            }

            progressFn?.Invoke(height, height);

            return(blocks);
        }