Ejemplo n.º 1
0
    private void ImportTexture(string name, TextureProcessingSettings settings)
    {
        string destinationPath = Path.Combine(destinationFolder.FullName, name + ".dds");

        if (new FileInfo(destinationPath).Exists)
        {
            return;
        }

        Console.WriteLine($"importing texture '{name}'...");

        using (var image = UnmanagedRgbaImage.Load(settings.File))  {
            using (var dilator = new TextureDilator(device, shaderCache)) {
                dilator.Dilate(settings.Mask, image.Size, settings.IsLinear, image.DataBox);
            }

            InputOptions input = new InputOptions();
            input.SetFormat(InputFormat.BGRA_8UB);
            input.SetTextureLayout(TextureType.Texture2D, image.Size.Width, image.Size.Height, 1);
            float gamma = settings.IsLinear ? 1f : 2.2f;
            input.SetGamma(gamma, gamma);
            input.SetMipmapData(image.PixelData, image.Size.Width, image.Size.Height, 1, 0, 0);
            input.SetAlphaMode(AlphaMode.None);

            input.SetMipmapGeneration(true);
            input.SetMipmapFilter(MipmapFilter.Kaiser);
            input.SetKaiserParameters(3, 4, 1);

            if (settings.Type == TextureProcessingType.Bump)
            {
                input.SetConvertToNormalMap(true);
                input.SetNormalFilter(1, 0, 0, 0);
                input.SetHeightEvaluation(1, 1, 1, 0);
            }
            else if (settings.Type == TextureProcessingType.Normal)
            {
                input.SetNormalMap(true);
            }

            CompressionOptions compression = new CompressionOptions();
            compression.SetQuality(Quality.Highest);
            compression.SetFormat(Format.RGBA);

            OutputOptions output = new OutputOptions();
            destinationFolder.CreateWithParents();
            output.SetFileName(destinationPath);
            output.SetContainer(Container.Container_DDS10);
            output.SetSrgbFlag(!settings.IsLinear);

            var  compressor = new Compressor();
            bool succeeded  = compressor.Compress(input, compression, output);
            if (!succeeded)
            {
                throw new InvalidOperationException("texture conversion failed");
            }

            //force the previous output handler to be destructed so that the file is flushed and closed
            output.SetFileName("nul");

            if (compress)
            {
                CompressTexture(new FileInfo(destinationPath), settings.Type, settings.IsLinear);
            }
        }
    }
Ejemplo n.º 2
0
        protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            if (!sourceBitmap.TryGetFormat(out SurfaceFormat sourceFormat))
            {
                return(false);
            }

            TryGetFormat(out SurfaceFormat format);

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (format == sourceFormat &&
                sourceRegion == new Rectangle(0, 0, Width, Height) &&
                sourceRegion == destinationRegion)
            {
                SetPixelData(sourceBitmap.GetPixelData());
                return(true);
            }

            // TODO: Add a XNA unit test to see what it does
            // my guess is that this is invalid for DXT.
            //
            // Destination region copy is not yet supported
            if (destinationRegion != new Rectangle(0, 0, Width, Height))
            {
                return(false);
            }

            if (sourceBitmap is PixelBitmapContent <RgbaVector> &&
                sourceRegion.Width == destinationRegion.Width &&
                sourceRegion.Height == destinationRegion.Height)
            {
                // NVTT wants 8bit data in BGRA format.
                var colorBitmap = new PixelBitmapContent <Bgra32>(sourceBitmap.Width, sourceBitmap.Height);
                Copy(sourceBitmap, colorBitmap);
                var sourceData = colorBitmap.GetPixelData();

                AlphaMode alphaMode;
                Format    outputFormat;
                bool      alphaDither = false;
                switch (format)
                {
                case SurfaceFormat.Dxt1:
                case SurfaceFormat.Dxt1SRgb:
                {
                    PrepareNVTT_DXT1(sourceData, out bool hasTransparency);
                    outputFormat = hasTransparency ? Format.DXT1a : Format.DXT1;
                    alphaMode    = hasTransparency ? AlphaMode.Transparency : AlphaMode.None;
                    alphaDither  = true;
                    break;
                }

                case SurfaceFormat.Dxt3:
                case SurfaceFormat.Dxt3SRgb:
                {
                    //PrepareNVTT(sourceData);
                    outputFormat = Format.DXT3;
                    alphaMode    = AlphaMode.Transparency;
                    break;
                }

                case SurfaceFormat.Dxt5:
                case SurfaceFormat.Dxt5SRgb:
                {
                    //PrepareNVTT(sourceData);
                    outputFormat = Format.DXT5;
                    alphaMode    = AlphaMode.Transparency;
                    break;
                }

                default:
                    throw new InvalidOperationException("Invalid DXT surface format!");
                }

                // Do all the calls to the NVTT wrapper within this handler
                // so we properly clean up if things blow up.
                var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned);
                try
                {
                    var dataPtr = dataHandle.AddrOfPinnedObject();

                    var inputOptions = new InputOptions();
                    inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1);
                    inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0);
                    inputOptions.SetMipmapGeneration(false);
                    inputOptions.SetGamma(1.0f, 1.0f);
                    inputOptions.SetAlphaMode(alphaMode);

                    var compressionOptions = new CompressionOptions();
                    compressionOptions.SetFormat(outputFormat);
                    compressionOptions.SetQuality(Quality.Normal);

                    // TODO: This isn't working which keeps us from getting the
                    // same alpha dither behavior on DXT1 as XNA.
                    //
                    // See https://github.com/MonoGame/MonoGame/issues/6259
                    //
                    //if (alphaDither)
                    //compressionOptions.SetQuantization(false, false, true);

                    var outputOptions = new OutputOptions();
                    outputOptions.SetOutputHeader(false);
                    outputOptions.SetOutputOptionsOutputHandler(NvttBeginImage, NvttWriteImage, NvttEndImage);

                    var dxtCompressor = new Compressor();
                    dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions);
                }
                finally
                {
                    dataHandle.Free();
                }
                return(true);
            }

            try
            {
                Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                return(true);
            }
            catch (InvalidOperationException)
            {
                return(false);
            }
        }
Ejemplo n.º 3
0
        public static unsafe bool Compress(this Texture2DInfo tex, TextureFormat format)
        {
            var data = tex.RawData;
            int width = tex.Width, height = tex.Height, pos, outPos;

            switch (format)
            {
            case TextureFormat.Alpha8:
            {
                pos = 0; outPos = 0;
                var out_ = new byte[width * height];

                fixed(byte *pOut = out_, pData = data)
                for (var y = 0; y < height; y++)
                {
                    for (var x = 0; x < width; x++)
                    {
                        var fR = pData[pos];
                        var fG = pData[pos + 1];
                        var fB = pData[pos + 2];
                        var fA = pData[pos + 3];
                        pOut[outPos] = (byte)(((fR + fB + fG) / 3) & 0XFF);
                        pos         += 4;
                        outPos      += 1;
                    }
                }
                tex.RawData = out_;

                return(true);
            }

            case TextureFormat.ARGB4444:
            case TextureFormat.RGB565:
            {
                pos = 0; outPos = 0;
                using (var pvrTexture = PVRTexture.CreateTexture(data, (uint)width, (uint)height, 1, PixelFormat.RGBA8888, true, VariableType.UnsignedByte, ColourSpace.sRGB))
                {
                    var doDither = true;
                    pvrTexture.Transcode(PixelFormat.RGBA4444, VariableType.UnsignedByte, ColourSpace.sRGB, format == TextureFormat.ARGB4444 ? CompressorQuality.PVRTCNormal : CompressorQuality.ETCMedium, doDither);
                    var texDataSize = pvrTexture.GetTextureDataSize(0);
                    var out_        = new byte[texDataSize];
                    pvrTexture.GetTextureData(out_, texDataSize);
                    if (format == TextureFormat.RGB565)
                    {
                        var data2 = out_;
                        out_ = new byte[texDataSize];

                        fixed(byte *pOut = out_, pData = data2)
                        for (var y = 0; y < height; y++)
                        {
                            for (var x = 0; x < width; x++)
                            {
                                var v0 = pData[pos];
                                var v1 = pData[pos + 1];
                                // 4bit little endian {A, B},{G, R}
                                var sA = v0 & 0xF0 >> 4;
                                var sB = (v0 & 0xF0) >> 4;
                                var sG = v1 & 0xF0 >> 4;
                                var sR = (v1 & 0xF0) >> 4;
                                // swap to little endian {B, G, R, A }
                                var fB = sB & 0xf;
                                var fG = sG & 0xf;
                                var fR = sR & 0xf;
                                var fA = sA & 0xf;
                                pOut[outPos]     = (byte)((fG << 4) + fB);
                                pOut[outPos + 1] = (byte)((fA << 4) + fR);
                                pos    += 2;
                                outPos += 2;
                            }
                        }
                    }
                    tex.RawData = out_;
                    return(true);
                }
            }

            case TextureFormat.RGB24:
            {
                pos = 0; outPos = 0;
                var out_ = new byte[width * height * 3];

                fixed(byte *pOut = out_, pData = data)
                for (var y = 0; y < height; y++)
                {
                    for (var x = 0; x < width; x++)
                    {
                        // 4bit little endian {A, B},{G, R}
                        var fR = pData[pos];
                        var fG = pData[pos + 1];
                        var fB = pData[pos + 2];
                        var fA = pData[pos + 3];
                        pOut[outPos]     = fR;
                        pOut[outPos + 1] = fG;
                        pOut[outPos + 2] = fB;
                        pos    += 4;
                        outPos += 3;
                    }
                }
                tex.RawData = out_;

                return(true);
            }

            case TextureFormat.RGBA32:
                return(true);

            case TextureFormat.ARGB32:
            {
                pos = 0; outPos = 0;
                var out_ = new byte[width * height * 4];

                fixed(byte *pOut = out_, pData = data)
                for (var y = 0; y < height; y++)
                {
                    for (var x = 0; x < width; x++)
                    {
                        var fA = pData[pos];
                        var fR = pData[pos + 1];
                        var fG = pData[pos + 2];
                        var fB = pData[pos + 3];
                        out_[outPos]     = fR;
                        out_[outPos + 1] = fG;
                        out_[outPos + 2] = fB;
                        out_[outPos + 3] = fA;
                        pos    += 4;
                        outPos += 4;
                    }
                }
                tex.RawData = out_;

                return(true);
            }

            //case TextureFormat.ATC_RGBA8:
            //case TextureFormat.ATC_RGB4:
            case TextureFormat.ETC2_RGBA8:
            case TextureFormat.ETC_RGB4:
                TextureConverterWrapper.CompressionFormat format2;
                switch (format)
                {
                //case TextureFormat.ATC_RGBA8: format2 = TextureConverterWrapper.CompressionFormat.AtcRgbaExplicitAlpha; break;
                //case TextureFormat.ATC_RGB4: format2 = TextureConverterWrapper.CompressionFormat.AtcRgb; break;
                case TextureFormat.ETC2_RGBA8: format2 = TextureConverterWrapper.CompressionFormat.Etc2Rgba; break;

                case TextureFormat.ETC_RGB4: format2 = TextureConverterWrapper.CompressionFormat.Etc1; break;

                default: throw new ArgumentOutOfRangeException(nameof(format), format.ToString());
                }
                tex.RawData = TextureConverterWrapper.Compress(data, width, height, format2);
                return(true);

            case TextureFormat.DXT1:
            case TextureFormat.DXT5:
            {
                var dxtCompressor = new Compressor();
                var inputOptions  = new InputOptions();
                inputOptions.SetAlphaMode(format == TextureFormat.DXT1 ? AlphaMode.None : AlphaMode.Premultiplied);
                inputOptions.SetTextureLayout(TextureType.Texture2D, width, height, 1);
                fixed(byte *pData = data)
                for (var x = 0; x < data.Length; x += 4)
                {
                    pData[x]     ^= pData[x + 2];
                    pData[x + 2] ^= pData[x];
                    pData[x]     ^= pData[x + 2];
                }

                var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
                try
                {
                    var dataPtr = dataHandle.AddrOfPinnedObject();
                    inputOptions.SetMipmapData(dataPtr, width, height, 1, 0, 0);
                    inputOptions.SetMipmapGeneration(false);
                    inputOptions.SetGamma(1.0f, 1.0f);
                    var compressionOptions = new CompressionOptions();
                    compressionOptions.SetFormat(format == TextureFormat.DXT1 ? Nvidia.TextureTools.Format.DXT1 : Nvidia.TextureTools.Format.DXT5);
                    compressionOptions.SetQuality(Quality.Normal);
                    var outputOptions = new OutputOptions();
                    outputOptions.SetOutputHeader(false);
                    var out_ = new byte[0];
                    using (var handler = new DxtDataHandler(out_, outputOptions))
                    {
                        dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions);
                        out_ = handler.dst;
                    }
                    tex.RawData = out_;
                    return(true);
                }
                finally { dataHandle.Free(); }
            }

            case TextureFormat.ASTC_RGBA_4x4:
            case TextureFormat.ASTC_RGB_4x4:
                AstcencWrapper.EncodeASTC(data, width, height, 4, 4, out tex.RawData);
                return(true);

            default: throw new ArgumentOutOfRangeException(nameof(format), format.ToString());
            }
        }
Ejemplo n.º 4
0
        protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
        {
            SurfaceFormat sourceFormat;

            if (!sourceBitmap.TryGetFormat(out sourceFormat))
            {
                return(false);
            }

            SurfaceFormat format;

            TryGetFormat(out format);

            // A shortcut for copying the entire bitmap to another bitmap of the same type and format
            if (format == sourceFormat && (sourceRegion == new Rectangle(0, 0, Width, Height)) && sourceRegion == destinationRegion)
            {
                SetPixelData(sourceBitmap.GetPixelData());
                return(true);
            }

            // Destination region copy is not yet supported
            if (destinationRegion != new Rectangle(0, 0, Width, Height))
            {
                return(false);
            }

            // If the source is not Vector4 or requires resizing, send it through BitmapContent.Copy
            if (!(sourceBitmap is PixelBitmapContent <Vector4>) || sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height)
            {
                try
                {
                    BitmapContent.Copy(sourceBitmap, sourceRegion, this, destinationRegion);
                    return(true);
                }
                catch (InvalidOperationException)
                {
                    return(false);
                }
            }

            //SquishFlags targetFormat = SquishFlags.ColourClusterFit;
            Format outputFormat = Format.DXT1;

            switch (format)
            {
            case SurfaceFormat.Dxt1:
                outputFormat = Format.DXT1;
                break;

            case SurfaceFormat.Dxt1SRgb:
                outputFormat = Format.DXT1;
                break;

            case SurfaceFormat.Dxt3:
                outputFormat = Format.DXT3;
                break;

            case SurfaceFormat.Dxt3SRgb:
                outputFormat = Format.DXT3;
                break;

            case SurfaceFormat.Dxt5:
                outputFormat = Format.DXT5;
                break;

            case SurfaceFormat.Dxt5SRgb:
                outputFormat = Format.DXT5;
                break;

            default:
                return(false);
            }

            // libsquish requires RGBA8888
            var colorBitmap = new PixelBitmapContent <Color>(sourceBitmap.Width, sourceBitmap.Height);

            BitmapContent.Copy(sourceBitmap, colorBitmap);

            var sourceData = colorBitmap.GetPixelData();

            /*
             * var dataSize = Squish.GetStorageRequirements(colorBitmap.Width, colorBitmap.Height, targetFormat);
             * var data = new byte[dataSize];
             * var metric = new float[] { 1.0f, 1.0f, 1.0f };
             * Squish.CompressImage(sourceData, colorBitmap.Width, colorBitmap.Height, data, targetFormat, metric);
             * SetPixelData(data);
             */

            var dxtCompressor = new Compressor();
            var inputOptions  = new InputOptions();

            if (outputFormat != Format.DXT1)
            {
                inputOptions.SetAlphaMode(AlphaMode.Premultiplied);
            }
            else
            {
                inputOptions.SetAlphaMode(AlphaMode.None);
            }
            inputOptions.SetTextureLayout(TextureType.Texture2D, colorBitmap.Width, colorBitmap.Height, 1);

            // Small hack here. NVTT wants 8bit data in BGRA. Flip the B and R channels
            // again here.
            GraphicsUtil.BGRAtoRGBA(sourceData);
            var dataHandle = GCHandle.Alloc(sourceData, GCHandleType.Pinned);

            try
            {
                var dataPtr = dataHandle.AddrOfPinnedObject();

                inputOptions.SetMipmapData(dataPtr, colorBitmap.Width, colorBitmap.Height, 1, 0, 0);
                inputOptions.SetMipmapGeneration(false);
                inputOptions.SetGamma(1.0f, 1.0f);

                var outputOptions = new OutputOptions();
                outputOptions.SetOutputHeader(false);

                var handler = new DxtDataHandler(this);
                outputOptions.SetOutputHandler(handler.BeginImage, handler.WriteData);

                var compressionOptions = new CompressionOptions();
                compressionOptions.SetFormat(outputFormat);
                compressionOptions.SetQuality(Quality.Normal);

                dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions);
            }
            finally
            {
                dataHandle.Free();
            }
            return(true);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Resizes the specified texture and/or generates mipmaps.
        /// </summary>
        /// <param name="texture">The texture.</param>
        /// <param name="width">The desired width.</param>
        /// <param name="height">The desired height.</param>
        /// <param name="inputGamma">The input gamma.</param>
        /// <param name="outputGamma">The output gamma.</param>
        /// <param name="generateMipmaps">
        /// <see langword="true"/> to generate all mipmap levels; otherwise <see langword="false"/>.
        /// </param>
        /// <param name="hasAlpha">
        /// <see langword="true"/> if <paramref name="texture"/> requires an alpha channel; otherwise,
        /// <see langword="false"/> if <paramref name="texture"/> is opaque.
        /// </param>
        /// <param name="hasFractionalAlpha">
        /// <see langword="true"/> if <paramref name="texture"/> contains fractional alpha values;
        /// otherwise, <see langword="false"/> if <paramref name="texture"/> is opaque or contains only
        /// binary alpha.
        /// </param>
        /// <param name="premultipliedAlpha">
        /// <see langword="true"/> when <paramref name="texture"/> is using premultiplied alpha.;
        /// otherwise, <see langword="false"/>.</param>
        /// <returns>The resized texture.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="texture"/> is <see langword="null"/>.
        /// </exception>
        public static Texture ResizeAndGenerateMipmaps(Texture texture, int width, int height, float inputGamma, float outputGamma, bool generateMipmaps, bool hasAlpha, bool hasFractionalAlpha, bool premultipliedAlpha)
        {
            if (texture == null)
            {
                throw new ArgumentNullException("texture");
            }

            // NVIDIA Texture Tools expect BGRA 8:8:8:8.
            if (texture.Description.Format != TextureFormat.B8G8R8A8_UNorm)
            {
                throw new ArgumentException("Texture format needs to be B8G8R8A8_UNORM.", "texture");
            }

            if (texture.Description.Dimension != TextureDimension.TextureCube && texture.Description.ArraySize > 1)
            {
                throw new NotSupportedException("Resizing and mipmap generation for texture arrays is not supported.");
            }
            if (texture.Description.Dimension == TextureDimension.Texture3D)
            {
                throw new NotSupportedException("Resizing and mipmap generation for volume textures is not supported.");
            }

            // ----- InputOptions
            var inputOptions = new InputOptions();

            inputOptions.SetAlphaMode(hasAlpha ? (premultipliedAlpha ? AlphaMode.Premultiplied : AlphaMode.Transparency)
                                         : AlphaMode.None);
            inputOptions.SetFormat(InputFormat.BGRA_8UB);
            inputOptions.SetGamma(inputGamma, outputGamma);
            inputOptions.SetMipmapFilter(MipmapFilter.Box);
            inputOptions.SetMipmapGeneration(generateMipmaps);
            bool roundToPowerOfTwo = (width != texture.Description.Width || height != texture.Description.Height);

            inputOptions.SetRoundMode(roundToPowerOfTwo ? RoundMode.ToNextPowerOfTwo : RoundMode.None);
            inputOptions.SetWrapMode(WrapMode.Mirror);

            var  description = texture.Description;
            bool isCube      = description.Dimension == TextureDimension.TextureCube;
            var  textureType = isCube ? TextureType.TextureCube : TextureType.Texture2D;

            inputOptions.SetTextureLayout(textureType, description.Width, description.Height, 1);

            for (int arrayIndex = 0; arrayIndex < description.ArraySize; arrayIndex++)
            {
                for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++)
                {
                    int index  = texture.GetImageIndex(mipIndex, arrayIndex, 0);
                    var image  = texture.Images[index];
                    var handle = GCHandle.Alloc(image.Data, GCHandleType.Pinned);
                    inputOptions.SetMipmapData(handle.AddrOfPinnedObject(), image.Width, image.Height, 1, arrayIndex, mipIndex);
                    handle.Free();
                }
            }

            // ----- OutputOptions
            var outputOptions = new OutputOptions();

            outputOptions.SetOutputHeader(false);
            outputOptions.Error += OnError;

            description.Format    = TextureFormat.R8G8B8A8_UNorm;
            description.Width     = width;
            description.Height    = height;
            description.MipLevels = generateMipmaps ? CalculateMipLevels(width, height) : 1;
            var resizedTexture = new Texture(description);
            var outputHandler  = new OutputHandler(resizedTexture);

            outputOptions.SetOutputHandler(outputHandler.BeginImage, outputHandler.WriteData);

            // ----- CompressionOptions
            var compressionOptions = new CompressionOptions();

            compressionOptions.SetFormat(Format.RGBA);
            compressionOptions.SetPixelFormat(32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
            compressionOptions.SetQuality(Quality.Normal);

            // ----- Run NVTT
            try
            {
                var compressor = new Compressor();
                compressor.Compress(inputOptions, compressionOptions, outputOptions);
            }
            catch (NullReferenceException)
            {
                // Resizing and mipmap generation without compression sometimes causes a
                // NullReferenceException in nvttCompress().
                throw new Exception("NullReferenceException in NVIDIA texture tools. Please try again.");
            }

            return(resizedTexture);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Compresses the specified texture using a Block Compression format (BC<i>n</i>).
        /// </summary>
        /// <param name="texture">The uncompressed texture.</param>
        /// <param name="inputGamma">The input gamma.</param>
        /// <param name="outputGamma">The output gamma.</param>
        /// <param name="generateMipmaps">
        /// <see langword="true"/> to generate all mipmap levels; otherwise <see langword="false"/>.
        /// </param>
        /// <param name="hasAlpha">
        /// <see langword="true"/> if <paramref name="texture"/> requires an alpha channel; otherwise,
        /// <see langword="false"/> if <paramref name="texture"/> is opaque.
        /// </param>
        /// <param name="hasFractionalAlpha">
        /// <see langword="true"/> if <paramref name="texture"/> contains fractional alpha values;
        /// otherwise, <see langword="false"/> if <paramref name="texture"/> is opaque or contains only
        /// binary alpha.
        /// </param>
        /// <param name="premultipliedAlpha">
        /// <see langword="true"/> when <paramref name="texture"/> is using premultiplied alpha.;
        /// otherwise, <see langword="false"/>.</param>
        /// <param name="sharpAlpha">
        /// <see langword="true"/> when the texture contains a sharp alpha mask; otherwise
        /// <see langword="false"/>.
        /// </param>
        /// <returns>The compressed texture.</returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="texture"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Texture width and height need to be equal (square texture) and  a power of two (POT
        /// texture).
        /// </exception>
        internal static Texture CompressBCn(Texture texture, float inputGamma, float outputGamma, bool generateMipmaps, bool hasAlpha, bool hasFractionalAlpha, bool premultipliedAlpha, bool sharpAlpha = false)
        {
            if (texture == null)
            {
                throw new ArgumentNullException("texture");
            }
            if (texture.Description.Dimension == TextureDimension.Texture3D)
            {
                throw new NotSupportedException("Texture compression for volume textures is not supported.");
            }

            // NVIDIA Texture Tools expect BGRA 8:8:8:8.
            texture = texture.ConvertTo(TextureFormat.B8G8R8A8_UNorm);

            // ----- InputOptions
            var inputOptions = new InputOptions();

            inputOptions.SetAlphaMode(hasAlpha ? (premultipliedAlpha ? AlphaMode.Premultiplied : AlphaMode.Transparency)
                                         : AlphaMode.None);
            inputOptions.SetFormat(InputFormat.BGRA_8UB);
            inputOptions.SetGamma(inputGamma, outputGamma);
            inputOptions.SetMipmapFilter(MipmapFilter.Box);
            inputOptions.SetMipmapGeneration(generateMipmaps);
            inputOptions.SetRoundMode(RoundMode.None); // Size is set explicitly.
            inputOptions.SetWrapMode(WrapMode.Mirror);

            var  description = texture.Description;
            bool isCube      = description.Dimension == TextureDimension.TextureCube;
            var  textureType = isCube ? TextureType.TextureCube : TextureType.Texture2D;

            inputOptions.SetTextureLayout(textureType, description.Width, description.Height, 1);

            for (int arrayIndex = 0; arrayIndex < description.ArraySize; arrayIndex++)
            {
                for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++)
                {
                    int index  = texture.GetImageIndex(mipIndex, arrayIndex, 0);
                    var image  = texture.Images[index];
                    var handle = GCHandle.Alloc(image.Data, GCHandleType.Pinned);
                    inputOptions.SetMipmapData(handle.AddrOfPinnedObject(), image.Width, image.Height, 1, arrayIndex, mipIndex);
                    handle.Free();
                }
            }

            // ----- OutputOptions
            var outputOptions = new OutputOptions();

            outputOptions.SetOutputHeader(false);
            outputOptions.Error += OnError;

            Format compressedFormat;

            if (hasAlpha)
            {
                if (sharpAlpha)
                {
                    compressedFormat   = Format.BC2;
                    description.Format = TextureFormat.BC2_UNorm;
                }
                else
                {
                    compressedFormat   = Format.BC3;
                    description.Format = TextureFormat.BC3_UNorm;
                }
            }
            else
            {
                compressedFormat   = Format.BC1;
                description.Format = TextureFormat.BC1_UNorm;
            }
            var compressedTexture = new Texture(description);
            var outputHandler     = new OutputHandler(compressedTexture);

            outputOptions.SetOutputHandler(outputHandler.BeginImage, outputHandler.WriteData);

            // ----- CompressionOptions
            var compressionOptions = new CompressionOptions();

            compressionOptions.SetFormat(compressedFormat);
            compressionOptions.SetQuality(Quality.Normal);

            // ----- Run NVTT
            try
            {
                var compressor = new Compressor();
                compressor.Compress(inputOptions, compressionOptions, outputOptions);
            }
            catch (NullReferenceException)
            {
                throw new Exception("NullReferenceException in NVIDIA texture tools. Please try again.");
            }

            return(compressedTexture);
        }
Ejemplo n.º 7
0
        private static void CompressDxt(GraphicsProfile profile, TextureContent content, bool generateMipmaps, bool premultipliedAlpha, bool sharpAlpha)
        {
            var texData = content.Faces[0][0];

            if (profile == GraphicsProfile.Reach)
            {
                if (!IsPowerOfTwo(texData.Width) || !IsPowerOfTwo(texData.Height))
                {
                    throw new PipelineException("DXT Compressed textures width and height must be powers of two in GraphicsProfile.Reach.");
                }
            }

            var pixelData = texData.GetPixelData();

            // Test the alpha channel to figure out if we have alpha.
            var containsAlpha     = false;
            var containsFracAlpha = false;

            for (var x = 3; x < pixelData.Length; x += 4)
            {
                if (pixelData[x] != 0xFF)
                {
                    containsAlpha = true;

                    if (pixelData[x] != 0x0)
                    {
                        containsFracAlpha = true;
                    }
                }
            }

            var _dxtCompressor = new Compressor();
            var inputOptions   = new InputOptions();

            if (containsAlpha)
            {
                inputOptions.SetAlphaMode(premultipliedAlpha ? AlphaMode.Premultiplied : AlphaMode.Transparency);
            }
            else
            {
                inputOptions.SetAlphaMode(AlphaMode.None);
            }
            inputOptions.SetTextureLayout(TextureType.Texture2D, texData.Width, texData.Height, 1);


            // Small hack here. NVTT wants 8bit data in BGRA. Flip the B and R channels
            // again here.
            GraphicsUtil.BGRAtoRGBA(pixelData);
            var dataHandle = GCHandle.Alloc(pixelData, GCHandleType.Pinned);
            var dataPtr    = dataHandle.AddrOfPinnedObject();

            inputOptions.SetMipmapData(dataPtr, texData.Width, texData.Height, 1, 0, 0);
            inputOptions.SetMipmapGeneration(generateMipmaps);
            inputOptions.SetGamma(1.0f, 1.0f);

            var outputOptions = new OutputOptions();

            outputOptions.SetOutputHeader(false);

            var outputFormat = Format.DXT1;

            if (containsFracAlpha)
            {
                if (sharpAlpha)
                {
                    outputFormat = Format.DXT3;
                }
                else
                {
                    outputFormat = Format.DXT5;
                }
            }

            var handler = new DxtDataHandler(content, outputFormat);

            outputOptions.SetOutputHandler(handler.BeginImage, handler.WriteData);

            var compressionOptions = new CompressionOptions();

            compressionOptions.SetFormat(outputFormat);
            compressionOptions.SetQuality(Quality.Normal);

            _dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions);

            dataHandle.Free();
        }