Пример #1
0
        /// <summary>
        /// Encodes all mipmap levels into a list of byte buffers.
        /// </summary>
        public List <byte[]> EncodeToRawBytes(Image <Rgba32> inputImage)
        {
            List <byte[]>   output              = new List <byte[]>();
            IBcBlockEncoder compressedEncoder   = null;
            IRawEncoder     uncompressedEncoder = null;

            if (OutputOptions.format.IsCompressedFormat())
            {
                compressedEncoder = GetEncoder(OutputOptions.format);
                if (compressedEncoder == null)
                {
                    throw new NotSupportedException($"This format is not supported: {OutputOptions.format}");
                }
            }
            else
            {
                uncompressedEncoder = GetRawEncoder(OutputOptions.format);
            }

            uint numMipMaps = (uint)OutputOptions.maxMipMapLevel;

            if (!OutputOptions.generateMipMaps)
            {
                numMipMaps = 1;
            }

            var mipChain = MipMapper.GenerateMipChain(inputImage, ref numMipMaps);

            for (int i = 0; i < numMipMaps; i++)
            {
                byte[] encoded = null;
                if (OutputOptions.format.IsCompressedFormat())
                {
                    var blocks = ImageToBlocks.ImageTo4X4(mipChain[i].Frames[0], out int blocksWidth, out int blocksHeight);
                    encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality,
                                                       !Debugger.IsAttached && Options.multiThreaded);
                }
                else
                {
                    encoded = uncompressedEncoder.Encode(mipChain[i].GetPixelSpan());
                }

                output.Add(encoded);
            }

            foreach (var image in mipChain)
            {
                image.Dispose();
            }

            return(output);
        }
Пример #2
0
        /// <summary>
        /// Encodes all cubemap faces and mipmap levels into a Dds file.
        /// Order is +X, -X, +Y, -Y, +Z, -Z. Back maps to positive Z and front to negative Z.
        /// </summary>
        public DdsFile EncodeCubeMapToDds(Image <Rgba32> right, Image <Rgba32> left, Image <Rgba32> top, Image <Rgba32> down,
                                          Image <Rgba32> back, Image <Rgba32> front)
        {
            DdsFile         output;
            IBcBlockEncoder compressedEncoder   = null;
            IRawEncoder     uncompressedEncoder = null;

            if (right.Width != left.Width || right.Width != top.Width || right.Width != down.Width ||
                right.Width != back.Width || right.Width != front.Width ||
                right.Height != left.Height || right.Height != top.Height || right.Height != down.Height ||
                right.Height != back.Height || right.Height != front.Height)
            {
                throw new ArgumentException("All input images of a cubemap should be the same size.");
            }

            Image <Rgba32>[] faces = new[] { right, left, top, down, back, front };

            if (OutputOptions.format.IsCompressedFormat())
            {
                compressedEncoder = GetEncoder(OutputOptions.format);
                if (compressedEncoder == null)
                {
                    throw new NotSupportedException($"This format is not supported: {OutputOptions.format}");
                }

                var(ddsHeader, dxt10Header) = DdsHeader.InitializeCompressed(right.Width, right.Height,
                                                                             compressedEncoder.GetDxgiFormat());
                output = new DdsFile(ddsHeader, dxt10Header);

                if (OutputOptions.ddsBc1WriteAlphaFlag &&
                    OutputOptions.format == CompressionFormat.BC1WithAlpha)
                {
                    output.Header.ddsPixelFormat.dwFlags |= PixelFormatFlags.DDPF_ALPHAPIXELS;
                }
            }
            else
            {
                uncompressedEncoder = GetRawEncoder(OutputOptions.format);
                var ddsHeader = DdsHeader.InitializeUncompressed(right.Width, right.Height,
                                                                 uncompressedEncoder.GetDxgiFormat());
                output = new DdsFile(ddsHeader);
            }

            uint numMipMaps = (uint)OutputOptions.maxMipMapLevel;

            if (!OutputOptions.generateMipMaps)
            {
                numMipMaps = 1;
            }

            for (int f = 0; f < faces.Length; f++)
            {
                var mipChain = MipMapper.GenerateMipChain(faces[f], ref numMipMaps);


                for (int mip = 0; mip < numMipMaps; mip++)
                {
                    byte[] encoded = null;
                    if (OutputOptions.format.IsCompressedFormat())
                    {
                        var blocks = ImageToBlocks.ImageTo4X4(mipChain[mip].Frames[0], out int blocksWidth, out int blocksHeight);
                        encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality,
                                                           !Debugger.IsAttached && Options.multiThreaded);
                    }
                    else
                    {
                        encoded = uncompressedEncoder.Encode(mipChain[mip].GetPixelSpan());
                    }

                    if (mip == 0)
                    {
                        output.Faces.Add(new DdsFace((uint)mipChain[mip].Width, (uint)mipChain[mip].Height,
                                                     (uint)encoded.Length, mipChain.Count));
                    }

                    output.Faces[f].MipMaps[mip] = new DdsMipMap(encoded,
                                                                 (uint)mipChain[mip].Width,
                                                                 (uint)mipChain[mip].Height);
                }

                foreach (var image in mipChain)
                {
                    image.Dispose();
                }
            }

            output.Header.dwCaps       |= HeaderCaps.DDSCAPS_COMPLEX;
            output.Header.dwMipMapCount = numMipMaps;
            if (numMipMaps > 1)
            {
                output.Header.dwCaps |= HeaderCaps.DDSCAPS_MIPMAP;
            }
            output.Header.dwCaps2 |= HeaderCaps2.DDSCAPS2_CUBEMAP |
                                     HeaderCaps2.DDSCAPS2_CUBEMAP_POSITIVEX |
                                     HeaderCaps2.DDSCAPS2_CUBEMAP_NEGATIVEX |
                                     HeaderCaps2.DDSCAPS2_CUBEMAP_POSITIVEY |
                                     HeaderCaps2.DDSCAPS2_CUBEMAP_NEGATIVEY |
                                     HeaderCaps2.DDSCAPS2_CUBEMAP_POSITIVEZ |
                                     HeaderCaps2.DDSCAPS2_CUBEMAP_NEGATIVEZ;

            return(output);
        }
Пример #3
0
        /// <summary>
        /// Encodes all cubemap faces and mipmap levels into a Ktx file.
        /// Order is +X, -X, +Y, -Y, +Z, -Z. Back maps to positive Z and front to negative Z.
        /// </summary>
        public KtxFile EncodeCubeMapToKtx(Image <Rgba32> right, Image <Rgba32> left, Image <Rgba32> top, Image <Rgba32> down,
                                          Image <Rgba32> back, Image <Rgba32> front)
        {
            KtxFile         output;
            IBcBlockEncoder compressedEncoder   = null;
            IRawEncoder     uncompressedEncoder = null;

            if (right.Width != left.Width || right.Width != top.Width || right.Width != down.Width ||
                right.Width != back.Width || right.Width != front.Width ||
                right.Height != left.Height || right.Height != top.Height || right.Height != down.Height ||
                right.Height != back.Height || right.Height != front.Height)
            {
                throw new ArgumentException("All input images of a cubemap should be the same size.");
            }

            Image <Rgba32>[] faces = new[] { right, left, top, down, back, front };

            if (OutputOptions.format.IsCompressedFormat())
            {
                compressedEncoder = GetEncoder(OutputOptions.format);
                if (compressedEncoder == null)
                {
                    throw new NotSupportedException($"This format is not supported: {OutputOptions.format}");
                }
                output = new KtxFile(
                    KtxHeader.InitializeCompressed(right.Width, right.Height,
                                                   compressedEncoder.GetInternalFormat(),
                                                   compressedEncoder.GetBaseInternalFormat()));
            }
            else
            {
                uncompressedEncoder = GetRawEncoder(OutputOptions.format);
                output = new KtxFile(
                    KtxHeader.InitializeUncompressed(right.Width, right.Height,
                                                     uncompressedEncoder.GetGlType(),
                                                     uncompressedEncoder.GetGlFormat(),
                                                     uncompressedEncoder.GetGlTypeSize(),
                                                     uncompressedEncoder.GetInternalFormat(),
                                                     uncompressedEncoder.GetBaseInternalFormat()));
            }
            uint numMipMaps = (uint)OutputOptions.maxMipMapLevel;

            if (!OutputOptions.generateMipMaps)
            {
                numMipMaps = 1;
            }

            uint mipLength = MipMapper.CalculateMipChainLength(right.Width, right.Height, numMipMaps);

            for (uint i = 0; i < mipLength; i++)
            {
                output.MipMaps.Add(new KtxMipmap(0, 0, 0, (uint)faces.Length));
            }

            for (int f = 0; f < faces.Length; f++)
            {
                var mipChain = MipMapper.GenerateMipChain(faces[f], ref numMipMaps);

                for (int i = 0; i < numMipMaps; i++)
                {
                    byte[] encoded = null;
                    if (OutputOptions.format.IsCompressedFormat())
                    {
                        var blocks = ImageToBlocks.ImageTo4X4(mipChain[i].Frames[0], out int blocksWidth, out int blocksHeight);
                        encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality,
                                                           !Debugger.IsAttached && Options.multiThreaded);
                    }
                    else
                    {
                        encoded = uncompressedEncoder.Encode(mipChain[i].GetPixelSpan());
                    }

                    if (f == 0)
                    {
                        output.MipMaps[i] = new KtxMipmap((uint)encoded.Length,
                                                          (uint)mipChain[i].Width,
                                                          (uint)mipChain[i].Height, (uint)faces.Length);
                    }

                    output.MipMaps[i].Faces[f] = new KtxMipFace(encoded,
                                                                (uint)mipChain[i].Width,
                                                                (uint)mipChain[i].Height);
                }

                foreach (var image in mipChain)
                {
                    image.Dispose();
                }
            }

            output.Header.NumberOfFaces        = (uint)faces.Length;
            output.Header.NumberOfMipmapLevels = mipLength;

            return(output);
        }
Пример #4
0
        /// <summary>
        /// Encodes a single mip level of the input image to a byte buffer.
        /// </summary>
        public byte[] EncodeToRawBytes(Image <Rgba32> inputImage, int mipLevel, out int mipWidth, out int mipHeight)
        {
            if (mipLevel < 0)
            {
                throw new ArgumentException($"{nameof(mipLevel)} cannot be less than zero.");
            }

            IBcBlockEncoder compressedEncoder   = null;
            IRawEncoder     uncompressedEncoder = null;

            if (OutputOptions.format.IsCompressedFormat())
            {
                compressedEncoder = GetEncoder(OutputOptions.format);
                if (compressedEncoder == null)
                {
                    throw new NotSupportedException($"This format is not supported: {OutputOptions.format}");
                }
            }
            else
            {
                uncompressedEncoder = GetRawEncoder(OutputOptions.format);
            }

            uint numMipMaps = (uint)OutputOptions.maxMipMapLevel;

            if (!OutputOptions.generateMipMaps)
            {
                numMipMaps = 1;
            }

            var mipChain = MipMapper.GenerateMipChain(inputImage, ref numMipMaps);

            if (mipLevel > numMipMaps - 1)
            {
                foreach (var image in mipChain)
                {
                    image.Dispose();
                }
                throw new ArgumentException($"{nameof(mipLevel)} cannot be more than number of mipmaps");
            }

            byte[] encoded = null;
            if (OutputOptions.format.IsCompressedFormat())
            {
                var blocks = ImageToBlocks.ImageTo4X4(mipChain[mipLevel].Frames[0], out int blocksWidth, out int blocksHeight);
                encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality,
                                                   !Debugger.IsAttached && Options.multiThreaded);
            }
            else
            {
                encoded = uncompressedEncoder.Encode(mipChain[mipLevel].GetPixelSpan());
            }

            mipWidth  = mipChain[mipLevel].Width;
            mipHeight = mipChain[mipLevel].Height;

            foreach (var image in mipChain)
            {
                image.Dispose();
            }

            return(encoded);
        }
Пример #5
0
        /// <summary>
        /// Encodes all mipmap levels into a Ktx file.
        /// </summary>
        public DdsFile EncodeToDds(Image <Rgba32> inputImage)
        {
            DdsFile         output;
            IBcBlockEncoder compressedEncoder   = null;
            IRawEncoder     uncompressedEncoder = null;

            if (OutputOptions.format.IsCompressedFormat())
            {
                compressedEncoder = GetEncoder(OutputOptions.format);
                if (compressedEncoder == null)
                {
                    throw new NotSupportedException($"This format is not supported: {OutputOptions.format}");
                }

                var(ddsHeader, dxt10Header) = DdsHeader.InitializeCompressed(inputImage.Width, inputImage.Height,
                                                                             compressedEncoder.GetDxgiFormat());
                output = new DdsFile(ddsHeader, dxt10Header);

                if (OutputOptions.ddsBc1WriteAlphaFlag &&
                    OutputOptions.format == CompressionFormat.BC1WithAlpha)
                {
                    output.Header.ddsPixelFormat.dwFlags |= PixelFormatFlags.DDPF_ALPHAPIXELS;
                }
            }
            else
            {
                uncompressedEncoder = GetRawEncoder(OutputOptions.format);
                var ddsHeader = DdsHeader.InitializeUncompressed(inputImage.Width, inputImage.Height,
                                                                 uncompressedEncoder.GetDxgiFormat());
                output = new DdsFile(ddsHeader);
            }

            uint numMipMaps = (uint)OutputOptions.maxMipMapLevel;

            if (!OutputOptions.generateMipMaps)
            {
                numMipMaps = 1;
            }

            var mipChain = MipMapper.GenerateMipChain(inputImage, ref numMipMaps);

            for (int mip = 0; mip < numMipMaps; mip++)
            {
                byte[] encoded = null;
                if (OutputOptions.format.IsCompressedFormat())
                {
                    var blocks = ImageToBlocks.ImageTo4X4(mipChain[mip].Frames[0], out int blocksWidth, out int blocksHeight);
                    encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality,
                                                       !Debugger.IsAttached && Options.multiThreaded);
                }
                else
                {
                    encoded = uncompressedEncoder.Encode(mipChain[mip].GetPixelSpan());
                }

                if (mip == 0)
                {
                    output.Faces.Add(new DdsFace((uint)inputImage.Width, (uint)inputImage.Height,
                                                 (uint)encoded.Length, (int)numMipMaps));
                }

                output.Faces[0].MipMaps[mip] = new DdsMipMap(encoded,
                                                             (uint)inputImage.Width,
                                                             (uint)inputImage.Height);
            }

            foreach (var image in mipChain)
            {
                image.Dispose();
            }

            output.Header.dwMipMapCount = numMipMaps;
            if (numMipMaps > 1)
            {
                output.Header.dwCaps |= HeaderCaps.DDSCAPS_COMPLEX | HeaderCaps.DDSCAPS_MIPMAP;
            }

            return(output);
        }
Пример #6
0
        /// <summary>
        /// Encodes all mipmap levels into a Ktx file.
        /// </summary>
        public KtxFile EncodeToKtx(Image <Rgba32> inputImage)
        {
            KtxFile         output;
            IBcBlockEncoder compressedEncoder   = null;
            IRawEncoder     uncompressedEncoder = null;

            if (OutputOptions.format.IsCompressedFormat())
            {
                compressedEncoder = GetEncoder(OutputOptions.format);
                if (compressedEncoder == null)
                {
                    throw new NotSupportedException($"This format is not supported: {OutputOptions.format}");
                }
                output = new KtxFile(
                    KtxHeader.InitializeCompressed(inputImage.Width, inputImage.Height,
                                                   compressedEncoder.GetInternalFormat(),
                                                   compressedEncoder.GetBaseInternalFormat()));
            }
            else
            {
                uncompressedEncoder = GetRawEncoder(OutputOptions.format);
                output = new KtxFile(
                    KtxHeader.InitializeUncompressed(inputImage.Width, inputImage.Height,
                                                     uncompressedEncoder.GetGlType(),
                                                     uncompressedEncoder.GetGlFormat(),
                                                     uncompressedEncoder.GetGlTypeSize(),
                                                     uncompressedEncoder.GetInternalFormat(),
                                                     uncompressedEncoder.GetBaseInternalFormat()));
            }

            uint numMipMaps = (uint)OutputOptions.maxMipMapLevel;

            if (!OutputOptions.generateMipMaps)
            {
                numMipMaps = 1;
            }

            var mipChain = MipMapper.GenerateMipChain(inputImage, ref numMipMaps);

            for (int i = 0; i < numMipMaps; i++)
            {
                byte[] encoded = null;
                if (OutputOptions.format.IsCompressedFormat())
                {
                    var blocks = ImageToBlocks.ImageTo4X4(mipChain[i].Frames[0], out int blocksWidth, out int blocksHeight);
                    encoded = compressedEncoder.Encode(blocks, blocksWidth, blocksHeight, OutputOptions.quality,
                                                       !Debugger.IsAttached && Options.multiThreaded);
                }
                else
                {
                    encoded = uncompressedEncoder.Encode(mipChain[i].GetPixelSpan());
                }

                output.MipMaps.Add(new KtxMipmap((uint)encoded.Length,
                                                 (uint)inputImage.Width,
                                                 (uint)inputImage.Height, 1));
                output.MipMaps[i].Faces[0] = new KtxMipFace(encoded,
                                                            (uint)inputImage.Width,
                                                            (uint)inputImage.Height);
            }

            foreach (var image in mipChain)
            {
                image.Dispose();
            }

            output.Header.NumberOfFaces        = 1;
            output.Header.NumberOfMipmapLevels = numMipMaps;

            return(output);
        }