예제 #1
0
        static public 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(context, 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));
                }
            }
        }
예제 #2
0
        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(context, content);
                return;
            }

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

            if (!IsPowerOfTwo(width) || !IsPowerOfTwo(height) || (width != height))
            {
                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(context, content);
                return;
            }

            var face = content.Faces[0][0];

            var alphaRange = CalculateAlphaRange(face);

            if (alphaRange == AlphaRange.Opaque)
            {
                content.ConvertBitmapType(typeof(PvrtcRgb4BitmapContent));
            }
            else
            {
                content.ConvertBitmapType(typeof(PvrtcRgba4BitmapContent));
            }
        }
예제 #3
0
        internal static void ChangeTextureToRequestedFormat(TextureContent texture,
                                                            Type originalType,
                                                            TextureProcessorOutputFormat textureFormat)
        {
            switch (textureFormat)
            {
                case TextureProcessorOutputFormat.NoChange:
                    if (originalType == null)
                    {
                        break;
                    }
                    texture.ConvertBitmapType(originalType);
                    return;

                case TextureProcessorOutputFormat.Color:
                    texture.ConvertBitmapType(typeof (PixelBitmapContent<Color>));
                    return;

                case TextureProcessorOutputFormat.DxtCompressed:
                    BestGuessCompress(texture);
                    break;

                default:
                    return;
            }
        }
예제 #4
0
        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);

            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));
            }
        }
예제 #5
0
 private static void BestGuessCompress(TextureContent texture)
 {
     texture.ConvertBitmapType(typeof (PixelBitmapContent<Color>));
     if (!(texture is Texture3DContent))
     {
         texture.ConvertBitmapType(HasFractionalAlpha(texture)
                                       ? typeof (Dxt5BitmapContent)
                                       : typeof (Dxt1BitmapContent));
     }
 }
예제 #6
0
        static void Compress(Type targetType, TextureContent content, bool generateMipMaps)
        {
            var wh = new object[2];

            if (generateMipMaps)
            {
                for (int i = 0; i < content.Faces.Count; ++i)
                {
                    // Only generate mipmaps if there are none already
                    if (content.Faces[i].Count == 1)
                    {
                        var src = content.Faces[i][0];
                        var w   = src.Width;
                        var h   = src.Height;

                        content.Faces[i].Clear();
                        wh[0] = w;
                        wh[1] = h;
                        var dest = (BitmapContent)Activator.CreateInstance(targetType, wh);
                        BitmapContent.Copy(src, dest);
                        content.Faces[i].Add(dest);
                        while (w > 1 && h > 1)
                        {
                            if (w > 1)
                            {
                                w = w >> 1;
                            }
                            if (h > 1)
                            {
                                h = h >> 1;
                            }
                            wh[0] = w;
                            wh[1] = h;
                            dest  = (BitmapContent)Activator.CreateInstance(targetType, wh);
                            BitmapContent.Copy(src, dest);
                            content.Faces[i].Add(dest);
                        }
                    }
                    else
                    {
                        // Convert the existing mipmaps
                        var chain = content.Faces[i];
                        for (int j = 0; j < chain.Count; ++j)
                        {
                            var src = chain[j];
                            wh[0] = src.Width;
                            wh[1] = src.Height;
                            var dest = (BitmapContent)Activator.CreateInstance(targetType, wh);
                            BitmapContent.Copy(src, dest);
                            chain[j] = dest;
                        }
                    }
                }
            }
            else
            {
                // Converts all existing faces and mipmaps
                content.ConvertBitmapType(targetType);
            }
        }
예제 #7
0
        /// <summary>
        /// Compresses TextureContent in a format appropriate to the platform
        /// </summary>
        public static void CompressTexture(GraphicsProfile profile, TextureContent content, TextureProcessorOutputFormat format, ContentProcessorContext context, bool generateMipmaps, bool sharpAlpha)
        {
            format = GetTextureFormatForPlatform(format, context.TargetPlatform);

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

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

            case TextureProcessorOutputFormat.Color16Bit:
                CompressColor16Bit(content, generateMipmaps);
                break;

            case TextureProcessorOutputFormat.DxtCompressed:
                CompressDxt(profile, content, generateMipmaps, sharpAlpha);
                break;

            case TextureProcessorOutputFormat.Etc1Compressed:
                CompressEtc1(content, generateMipmaps);
                break;

            case TextureProcessorOutputFormat.PvrCompressed:
                CompressPvrtc(content, generateMipmaps);
                break;
            }
        }
        private TextureContent GenerateCubemap(TextureContent input, ContentProcessorContext context)
        {
            if (input.Faces[1].Count != 0)
            {
                //its already a cubemap
                return base.Process(input, context);
            }
            TextureCubeContent cubeContent = new TextureCubeContent();
            // Convert the input data to Color format, for ease of processing.
            input.ConvertBitmapType(typeof(PixelBitmapContent<Color>));

            int height = input.Faces[0][0].Height;
            int width = input.Faces[0][0].Width / 6;

            //split the image into 6 pieces, setup: X+,X-, Y+,Y-, Z+, Z-
            cubeContent.Faces[(int)CubeMapFace.PositiveX] = CreateFace(input.Faces[0][0], width, height, 0);
            cubeContent.Faces[(int)CubeMapFace.NegativeX] = CreateFace(input.Faces[0][0], width, height, width * 1);
            cubeContent.Faces[(int)CubeMapFace.PositiveY] = CreateFace(input.Faces[0][0], width, height, width * 2);
            cubeContent.Faces[(int)CubeMapFace.NegativeY] = CreateFace(input.Faces[0][0], width, height, width * 3);
            cubeContent.Faces[(int)CubeMapFace.PositiveZ] = CreateFace(input.Faces[0][0], width, height, width * 4);
            cubeContent.Faces[(int)CubeMapFace.NegativeZ] = CreateFace(input.Faces[0][0], width, height, width * 5);

            // Calculate mipmap data.
            cubeContent.GenerateMipmaps(true);

            // Compress the cubemap into DXT1 format.
            cubeContent.ConvertBitmapType(typeof(Dxt1BitmapContent));
            return cubeContent;
        }
        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 <Vector4>));

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

            case TextureProcessorOutputFormat.Color16Bit:
                GraphicsUtil.CompressColor16Bit(context, 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 override TextureContent Process(TextureContent input, ContentProcessorContext context)
        {
            input.ConvertBitmapType(typeof(PixelBitmapContent<Color>));

            foreach (MipmapChain mipChain in input.Faces)
            {
                foreach (PixelBitmapContent<Color> bitmap in mipChain)
                {
                    for (int y = 0; y < bitmap.Height; y++)
                    {
                        for (int x = 0; x < bitmap.Width; x++)
                        {
                            Color c = bitmap.GetPixel(x, y);

                            c.R = (byte)(c.R * c.A / 255);
                            c.G = (byte)(c.G * c.A / 255);
                            c.B = (byte)(c.B * c.A / 255);

                            bitmap.SetPixel(x, y, c);
                        }
                    }
                }
            }

            return base.Process(input, context);
        }
예제 #11
0
        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));
            }
        }
예제 #12
0
        static public void CompressColor16Bit(ContentProcessorContext context, 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>));
            }
        }
예제 #13
0
        static public void CompressAti(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(context, 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));
            }
        }
예제 #14
0
        /// <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="generateMipmaps">If mipmap generation is required.</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 generateMipmaps, 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>));
                if (generateMipmaps)
                {
                    content.GenerateMipmaps(false);
                }
                return;
            }

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

            try
            {
                // All other formats require platform specific choices.
                PlatformCompressTexture(context, content, format, generateMipmaps, isSpriteFont);
            }
            catch (EntryPointNotFoundException ex)
            {
                context.Logger.LogImportantMessage("Could not find the entry point to compress the texture. " + ex.ToString());
                throw ex;
            }
            catch (DllNotFoundException ex)
            {
                context.Logger.LogImportantMessage("Could not compress texture. Required shared lib is missing. " + ex.ToString());
                throw ex;
            }
            catch (Exception ex)
            {
                context.Logger.LogImportantMessage("Could not convert texture. " + ex.ToString());
                throw ex;
            }
        }
        public override TextureContent Process(TextureContent input, ContentProcessorContext context)
        {
            input.ConvertBitmapType(typeof(PixelBitmapContent<Color>));
            foreach (var mipmapChain in input.Faces)
            {
                for (int i = 0; i < mipmapChain.Count; i++)
                {
                    var bitmap = mipmapChain[i] as PixelBitmapContent<Color>;

                    int newWidth = (int) ((float) bitmap.Width * Scale);
                    int newHeight = (int) ((float) bitmap.Height * Scale);

                    var newBitmap = new PixelBitmapContent<Color>(newWidth, newHeight);

                    for (int y = 0; y < bitmap.Height; y++)
                    {
                        for (int x = 0; x < bitmap.Width; x++)
                        {
                            for (int scaleY = 0; scaleY < Scale; scaleY++)
                            {
                                for (int scaleX = 0; scaleX < Scale; scaleX++)
                                {
                                    newBitmap.SetPixel(
                                        (int) (x * Scale) + scaleX,
                                        (int) (y * Scale) + scaleY,
                                        bitmap.GetPixel(x, y));
                                }
                            }
                        }
                    }

                    mipmapChain[i] = newBitmap;
                }
            }

            return base.Process(input, context);
        }
예제 #16
0
        /// <summary>
        /// Compresses TextureContent in a format appropriate to the platform
        /// </summary>
        public static void CompressTexture(GraphicsProfile profile, TextureContent content, TextureProcessorOutputFormat format, ContentProcessorContext context, bool generateMipmaps, bool sharpAlpha)
        {
            format = GetTextureFormatForPlatform(format, context.TargetPlatform);

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

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

                case TextureProcessorOutputFormat.Color16Bit:
                    CompressColor16Bit(content, generateMipmaps);
                    break;

                case TextureProcessorOutputFormat.DxtCompressed:
                    CompressDxt(profile, content, generateMipmaps, sharpAlpha);
                    break;

                case TextureProcessorOutputFormat.Etc1Compressed:
                    CompressEtc1(content, generateMipmaps);
                    break;

                case TextureProcessorOutputFormat.PvrCompressed:
                    CompressPvrtc(content, generateMipmaps);
                    break;
            }
        }
예제 #17
0
        static void Compress(Type targetType, TextureContent content, bool generateMipMaps)
        {
            var wh = new object[2];
            if (generateMipMaps)
            {
                for (int i = 0; i < content.Faces.Count; ++i)
                {
                    // Only generate mipmaps if there are none already
                    if (content.Faces[i].Count == 1)
                    {
                        var src = content.Faces[i][0];
                        var w = src.Width;
                        var h = src.Height;

                        content.Faces[i].Clear();
                        wh[0] = w;
                        wh[1] = h;
                        var dest = (BitmapContent)Activator.CreateInstance(targetType, wh);
                        BitmapContent.Copy(src, dest);
                        content.Faces[i].Add(dest);
                        while (w > 1 && h > 1)
                        {
                            if (w > 1)
                                w = w >> 1;
                            if (h > 1)
                                h = h >> 1;
                            wh[0] = w;
                            wh[1] = h;
                            dest = (BitmapContent)Activator.CreateInstance(targetType, wh);
                            BitmapContent.Copy(src, dest);
                            content.Faces[i].Add(dest);
                        }
                    }
                    else
                    {
                        // Convert the existing mipmaps
                        var chain = content.Faces[i];
                        for (int j = 0; j < chain.Count; ++j)
                        {
                            var src = chain[j];
                            wh[0] = src.Width;
                            wh[1] = src.Height;
                            var dest = (BitmapContent)Activator.CreateInstance(targetType, wh);
                            BitmapContent.Copy(src, dest);
                            chain[j] = dest;
                        }
                    }
                }
            }
            else
            {
                // Converts all existing faces and mipmaps
                content.ConvertBitmapType(targetType);
            }
        }