예제 #1
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;
        }
예제 #2
0
        private static void CompressDxt(TextureContent content, bool generateMipmaps)
        {
            var texData = content.Faces[0][0];

            if (!IsPowerOfTwo(texData.Width) || !IsPowerOfTwo(texData.Height))
                throw new PipelineException("DXT Compressed textures width and height must be powers of two.");

            var _dxtCompressor = new Compressor();
            var inputOptions = new InputOptions();
            inputOptions.SetAlphaMode(AlphaMode.Transparency);
            inputOptions.SetTextureLayout(TextureType.Texture2D, texData.Width, texData.Height, 1);

            var pixelData = texData.GetPixelData();
            
            // 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);

            var containsFracAlpha = ContainsFractionalAlpha(pixelData);
            var outputOptions = new OutputOptions();
            outputOptions.SetOutputHeader(false);

            var outputFormat = containsFracAlpha ? Format.DXT5 : Format.DXT1;

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

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

            _dxtCompressor.Compress(inputOptions, compressionOptions, outputOptions);

            dataHandle.Free();
        }
예제 #3
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;
        }
예제 #4
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;
        }
예제 #5
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();
        }