Exemple #1
0
        protected override void PlatformCompressTexture(
            ContentProcessorContext context, TextureContent content,
            TextureProcessorOutputFormat format, bool isSpriteFont)
        {
            format = GetTextureFormatForPlatform(format, context.TargetPlatform);

            // Make sure we're in a floating point format
            content.ConvertBitmapType(typeof(PixelBitmapContent <RgbaVector>));

            switch (format)
            {
            case TextureProcessorOutputFormat.AtcCompressed:
                GraphicsUtil.CompressAti(content, isSpriteFont);
                break;

            case TextureProcessorOutputFormat.Color16Bit:
                GraphicsUtil.CompressColor16Bit(content);
                break;

            case TextureProcessorOutputFormat.DxtCompressed:
                GraphicsUtil.CompressDxt(context, content, isSpriteFont);
                break;

            case TextureProcessorOutputFormat.Etc1Compressed:
                GraphicsUtil.CompressEtc1(context, content, isSpriteFont);
                break;

            case TextureProcessorOutputFormat.PvrCompressed:
                GraphicsUtil.CompressPvrtc(context, content, isSpriteFont);
                break;
            }
        }
        public static void CompressDxt(ContentProcessorContext context, TextureContent content, bool isSpriteFont)
        {
            var face = content.Faces[0][0];

            if (context.TargetProfile == GraphicsProfile.Reach)
            {
                if (!IsPowerOfTwo(face.Width) || !IsPowerOfTwo(face.Height))
                {
                    throw new PipelineException(
                              "DXT compression requires width and height must " +
                              "be powers of two in Reach graphics profile.");
                }
            }

            // Test the alpha channel to figure out if we have alpha.
            var alphaRange = CalculateAlphaRange(face);

            // TODO: This isn't quite right.
            //
            // We should be generating DXT1 textures for cutout alpha
            // as DXT1 supports 1bit alpha and it uses less memory.
            //
            // XNA never generated DXT3 for textures... it always picked
            // between DXT1 for cutouts and DXT5 for fractional alpha.
            //
            // DXT3 however can produce better results for high frequency
            // alpha like a chain link fence where is DXT5 is better for
            // low frequency alpha like clouds. I don't know how we can
            // pick the right thing in this case without a hint.

            if (isSpriteFont)
            {
                CompressFontDXT3(content);
            }
            else if (alphaRange == AlphaRange.Opaque)
            {
                content.ConvertBitmapType(typeof(Dxt1BitmapContent));
            }
            else if (alphaRange == AlphaRange.Cutout)
            {
                content.ConvertBitmapType(typeof(Dxt3BitmapContent));
            }
            else
            {
                content.ConvertBitmapType(typeof(Dxt5BitmapContent));
            }
        }
        public static void CompressColor16Bit(TextureContent content)
        {
            var face       = content.Faces[0][0];
            var alphaRange = CalculateAlphaRange(face);

            if (alphaRange == AlphaRange.Opaque)
            {
                content.ConvertBitmapType(typeof(PixelBitmapContent <Bgr565>));
            }
            else if (alphaRange == AlphaRange.Cutout)
            {
                content.ConvertBitmapType(typeof(PixelBitmapContent <Bgra5551>));
            }
            else
            {
                content.ConvertBitmapType(typeof(PixelBitmapContent <Bgra4444>));
            }
        }
        /// <summary>
        /// Performs conversion of the texture content to the correct format.
        /// </summary>
        /// <param name="context">The processor context.</param>
        /// <param name="content">The content to be compressed.</param>
        /// <param name="format">The user requested format for compression.</param>
        /// <param name="isSpriteFont">If the texture has represents a sprite font, i.e. is greyscale and has sharp black/white contrast.</param>
        public void ConvertTexture(
            ContentProcessorContext context, TextureContent content, TextureProcessorOutputFormat format, bool isSpriteFont)
        {
            // We do nothing in this case.
            if (format == TextureProcessorOutputFormat.NoChange)
            {
                return;
            }

            // If this is color just make sure the format is right and return it.
            if (format == TextureProcessorOutputFormat.Color)
            {
                content.ConvertBitmapType(typeof(PixelBitmapContent <Color>));
                return;
            }

            // Handle this common compression format.
            if (format == TextureProcessorOutputFormat.Color16Bit)
            {
                GraphicsUtil.CompressColor16Bit(content);
                return;
            }

            try
            {
                // All other formats require platform specific choices.
                PlatformCompressTexture(context, content, format, isSpriteFont);
            }
            catch (EntryPointNotFoundException ex)
            {
                context.Logger.LogImportantMessage("Could not find the entry point to compress the texture. " + ex.ToString());
                throw;
            }
            catch (DllNotFoundException ex)
            {
                context.Logger.LogImportantMessage("Could not compress texture. Required shared lib is missing. " + ex.ToString());
                throw;
            }
            catch (Exception ex)
            {
                context.Logger.LogImportantMessage("Could not convert texture. " + ex.ToString());
                throw;
            }
        }
        public static void CompressAti(TextureContent content, bool isSpriteFont)
        {
            // If sharp alpha is required (for a font texture page), use 16-bit color instead of PVR
            if (isSpriteFont)
            {
                CompressColor16Bit(content);
                return;
            }

            var face       = content.Faces[0][0];
            var alphaRange = CalculateAlphaRange(face);

            if (alphaRange == AlphaRange.Full)
            {
                content.ConvertBitmapType(typeof(AtcExplicitBitmapContent));
            }
            else
            {
                content.ConvertBitmapType(typeof(AtcInterpolatedBitmapContent));
            }
        }
        public static void CompressEtc1(ContentProcessorContext context, TextureContent content, bool isSpriteFont)
        {
            // If sharp alpha is required (for a font texture page), use 16-bit color instead of PVR
            if (isSpriteFont)
            {
                CompressColor16Bit(content);
                return;
            }

            var face       = content.Faces[0][0];
            var alphaRange = CalculateAlphaRange(face);

            // Use BGRA4444 for textures with non-opaque alpha values
            if (alphaRange != AlphaRange.Opaque)
            {
                content.ConvertBitmapType(typeof(PixelBitmapContent <Bgra4444>));
            }
            else
            {
                // PVR SGX does not handle non-POT ETC1 textures.
                // https://code.google.com/p/libgdx/issues/detail?id=1310
                // Since we already enforce POT for PVR and DXT in Reach, we will also enforce POT for ETC1
                if (!IsPowerOfTwo(face.Width) || !IsPowerOfTwo(face.Height))
                {
                    context.Logger.LogWarning(
                        null, content.Identity,
                        "ETC1 compression requires width and height to be powers of two due to " +
                        "hardware restrictions on some devices. Falling back to BGR565.");

                    content.ConvertBitmapType(typeof(PixelBitmapContent <Bgr565>));
                }
                else
                {
                    content.ConvertBitmapType(typeof(Etc1BitmapContent));
                }
            }
        }
        public static void CompressPvrtc(ContentProcessorContext context, TextureContent content, bool isSpriteFont)
        {
            // If sharp alpha is required (for a font texture page), use 16-bit color instead of PVR
            if (isSpriteFont)
            {
                CompressColor16Bit(content);
                return;
            }

            // Calculate number of mip levels
            int width  = content.Faces[0][0].Height;
            int height = content.Faces[0][0].Width;

            if (IsPowerOfTwo(width) && IsPowerOfTwo(height) && width == height)
            {
                var face       = content.Faces[0][0];
                var alphaRange = CalculateAlphaRange(face);

                if (alphaRange == AlphaRange.Opaque)
                {
                    content.ConvertBitmapType(typeof(PvrtcRgb4BitmapContent));
                }
                else
                {
                    content.ConvertBitmapType(typeof(PvrtcRgba4BitmapContent));
                }
            }
            else
            {
                context.Logger.LogWarning(
                    null, content.Identity,
                    "PVR compression requires width and height to " +
                    "be powers of two and equal. Falling back to 16-bit color.");

                CompressColor16Bit(content);
            }
        }
 protected abstract void PlatformCompressTexture(
     ContentProcessorContext context, TextureContent content, TextureProcessorOutputFormat format, bool isSpriteFont);
        // Compress the greyscale font texture page using a specially-formulated DXT3 mode
        public static unsafe void CompressFontDXT3(TextureContent content)
        {
            if (content.Faces.Count > 1)
            {
                throw new PipelineException("Font textures should only have one face");
            }

            Span <Vector4> block = stackalloc Vector4[16];

            for (int i = 0; i < content.Faces[0].Count; ++i)
            {
                var    face     = content.Faces[0][i];
                var    xBlocks  = (face.Width + 3) / 4;
                var    yBlocks  = (face.Height + 3) / 4;
                var    dxt3Size = xBlocks * yBlocks * 16;
                byte[] buffer   = new byte[dxt3Size];

                var facePixels = face.GetPixelData();
                fixed(byte *b = facePixels)
                {
                    var colors = (Vector4 *)b;

                    int w;
                    int h = 0;
                    int x;
                    int y = 0;

                    while (h < (face.Height & ~3))
                    {
                        w = 0;
                        x = 0;

                        var h0 = h * face.Width;
                        var h1 = h0 + face.Width;
                        var h2 = h1 + face.Width;
                        var h3 = h2 + face.Width;

                        while (w < (face.Width & ~3))
                        {
                            block[0]  = colors[w + h0];
                            block[1]  = colors[w + h0 + 1];
                            block[2]  = colors[w + h0 + 2];
                            block[3]  = colors[w + h0 + 3];
                            block[4]  = colors[w + h1];
                            block[5]  = colors[w + h1 + 1];
                            block[6]  = colors[w + h1 + 2];
                            block[7]  = colors[w + h1 + 3];
                            block[8]  = colors[w + h2];
                            block[9]  = colors[w + h2 + 1];
                            block[10] = colors[w + h2 + 2];
                            block[11] = colors[w + h2 + 3];
                            block[12] = colors[w + h3];
                            block[13] = colors[w + h3 + 1];
                            block[14] = colors[w + h3 + 2];
                            block[15] = colors[w + h3 + 3];

                            int offset = (x + y * xBlocks) * 16;
                            CompressFontDXT3Block(block, buffer, offset);

                            w += 4;
                            ++x;
                        }

                        // Do partial block at end of row
                        if (w < face.Width)
                        {
                            var cols = face.Width - w;
                            block.Clear();
                            for (int r = 0; r < 4; ++r)
                            {
                                h0 = (h + r) * face.Width;
                                for (int c = 0; c < cols; ++c)
                                {
                                    block[(r * 4) + c] = colors[w + h0 + c];
                                }
                            }

                            int offset = (x + y * xBlocks) * 16;
                            CompressFontDXT3Block(block, buffer, offset);
                        }

                        h += 4;
                        y++;
                    }

                    // Do last partial row
                    if (h < face.Height)
                    {
                        var rows = face.Height - h;
                        w = 0;
                        x = 0;
                        while (w < (face.Width & ~3))
                        {
                            block.Clear();
                            for (int r = 0; r < rows; ++r)
                            {
                                var h0 = (h + r) * face.Width;
                                block[(r * 4) + 0] = colors[w + h0 + 0];
                                block[(r * 4) + 1] = colors[w + h0 + 1];
                                block[(r * 4) + 2] = colors[w + h0 + 2];
                                block[(r * 4) + 3] = colors[w + h0 + 3];
                            }

                            int offset = (x + y * xBlocks) * 16;
                            CompressFontDXT3Block(block, buffer, offset);

                            w += 4;
                            x++;
                        }

                        // Do last partial block
                        if (w < face.Width)
                        {
                            var cols = face.Width - w;
                            block.Clear();
                            for (int r = 0; r < rows; ++r)
                            {
                                var h0 = (h + r) * face.Width;
                                for (int c = 0; c < cols; ++c)
                                {
                                    block[(r * 4) + c] = colors[w + h0 + c];
                                }
                            }

                            int offset = (x + y * xBlocks) * 16;
                            CompressFontDXT3Block(block, buffer, offset);
                        }
                    }
                }

                var dxt3 = new Dxt3BitmapContent(face.Width, face.Height);
                dxt3.SetPixelData(buffer);
                content.Faces[0][i] = dxt3;
            }
        }