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)); } } }
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)); } }
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; } }
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)); } }
private static void BestGuessCompress(TextureContent texture) { texture.ConvertBitmapType(typeof (PixelBitmapContent<Color>)); if (!(texture is Texture3DContent)) { texture.ConvertBitmapType(HasFractionalAlpha(texture) ? typeof (Dxt5BitmapContent) : typeof (Dxt1BitmapContent)); } }
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); } }
/// <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); }
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)); } }
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>)); } }
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)); } }
/// <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); }
/// <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; } }
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); } }