private static TextureContent Compress(Type bitmapContentType, Texture texture, ContentIdentity identity) { // Let MonoGame's BitmapContent handle the compression. var description = texture.Description; switch (description.Dimension) { case TextureDimension.Texture1D: case TextureDimension.Texture2D: { var textureContent = new Texture2DContent { Identity = identity }; for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++) { var image = texture.Images[texture.GetImageIndex(mipIndex, 0, 0)]; var sourceBitmap = TextureHelper.ToContent(image); var targetBitmap = (BitmapContent)Activator.CreateInstance(bitmapContentType, image.Width, image.Height); BitmapContent.Copy(sourceBitmap, targetBitmap); textureContent.Mipmaps.Add(targetBitmap); } return textureContent; } case TextureDimension.TextureCube: { var textureContent = new TextureCubeContent { Identity = identity }; for (int faceIndex = 0; faceIndex < 6; faceIndex++) { for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++) { var image = texture.Images[texture.GetImageIndex(mipIndex, faceIndex, 0)]; var sourceBitmap = TextureHelper.ToContent(image); var targetBitmap = (BitmapContent)Activator.CreateInstance(bitmapContentType, image.Width, image.Height); BitmapContent.Copy(sourceBitmap, targetBitmap); textureContent.Faces[faceIndex].Add(targetBitmap); } } return textureContent; } case TextureDimension.Texture3D: { var textureContent = new Texture3DContent { Identity = identity }; for (int zIndex = 0; zIndex < description.Depth; zIndex++) { textureContent.Faces.Add(new MipmapChain()); for (int mipIndex = 0; mipIndex < description.MipLevels; mipIndex++) { var image = texture.Images[texture.GetImageIndex(mipIndex, 0, zIndex)]; var sourceBitmap = TextureHelper.ToContent(image); var targetBitmap = (BitmapContent)Activator.CreateInstance(bitmapContentType, image.Width, image.Height); BitmapContent.Copy(sourceBitmap, targetBitmap); textureContent.Faces[zIndex].Add(targetBitmap); } } return textureContent; } } throw new InvalidOperationException("Invalid texture dimension."); }
internal static void WriteTexture(object spriteFontContent, bool alphaOnly, ContentProcessorContext context, string filename) { dynamic sfc = ExposedObject.From(spriteFontContent); // Get a copy of the texture in Color format Texture2DContent originalTexture = sfc.Texture; BitmapContent originalBitmap = originalTexture.Mipmaps[0]; PixelBitmapContent <Color> colorBitmap = new PixelBitmapContent <Color>( originalBitmap.Width, originalBitmap.Height); BitmapContent.Copy(originalBitmap, colorBitmap); Bitmap bitmap = new Bitmap(colorBitmap.Width, colorBitmap.Height, PixelFormat.Format32bppArgb); for (int x = 0; x < colorBitmap.Width; x++) { for (int y = 0; y < colorBitmap.Height; y++) { Color c = colorBitmap.GetPixel(x, y); if (alphaOnly) { c.R = 255; c.G = 255; c.B = 255; // Undo premultiplication } bitmap.SetPixel(x, y, System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B)); } } bitmap.Save(filename, ImageFormat.Png); bitmap.Dispose(); context.AddOutputFile(filename); }
public void BitmapCompressFullResize() { var b1 = new PixelBitmapContent <Color>(16, 16); Fill(b1, Color.Red); var b2 = new Dxt1BitmapContent(8, 8); BitmapContent.Copy(b1, b2); }
/// <summary> /// Once the arranging is complete, copies the bitmap data for each /// sprite to its chosen position in the single larger output bitmap. /// </summary> static BitmapContent CopySpritesToOutput(List <ArrangedSprite> sprites, IList <BitmapContent> sourceSprites, ICollection <Rectangle> outputSprites, int width, int height) { BitmapContent output = new PixelBitmapContent <Color>(width, height); foreach (ArrangedSprite sprite in sprites) { BitmapContent source = sourceSprites[sprite.Index]; int x = sprite.X; int y = sprite.Y; int w = source.Width; int h = source.Height; // Copy the main sprite data to the output sheet. BitmapContent.Copy(source, new Rectangle(0, 0, w, h), output, new Rectangle(x + 1, y + 1, w, h)); // Copy a border strip from each edge of the sprite, creating // a one pixel padding area to avoid filtering problems if the // sprite is scaled or rotated. BitmapContent.Copy(source, new Rectangle(0, 0, 1, h), output, new Rectangle(x, y + 1, 1, h)); BitmapContent.Copy(source, new Rectangle(w - 1, 0, 1, h), output, new Rectangle(x + w + 1, y + 1, 1, h)); BitmapContent.Copy(source, new Rectangle(0, 0, w, 1), output, new Rectangle(x + 1, y, w, 1)); BitmapContent.Copy(source, new Rectangle(0, h - 1, w, 1), output, new Rectangle(x + 1, y + h + 1, w, 1)); // Copy a single pixel from each corner of the sprite, // filling in the corners of the one pixel padding area. BitmapContent.Copy(source, new Rectangle(0, 0, 1, 1), output, new Rectangle(x, y, 1, 1)); BitmapContent.Copy(source, new Rectangle(w - 1, 0, 1, 1), output, new Rectangle(x + w + 1, y, 1, 1)); BitmapContent.Copy(source, new Rectangle(0, h - 1, 1, 1), output, new Rectangle(x, y + h + 1, 1, 1)); BitmapContent.Copy(source, new Rectangle(w - 1, h - 1, 1, 1), output, new Rectangle(x + w + 1, y + h + 1, 1, 1)); // Remember where we placed this sprite. outputSprites.Add(new Rectangle(x + 1, y + 1, w, h)); } return(output); }
void BitmapCompressFullResize <T>(T color1) where T : struct, IEquatable <T> { var b1 = new PixelBitmapContent <T>(16, 16); Fill(b1, color1); var b2 = new Dxt1BitmapContent(8, 8); BitmapContent.Copy(b1, b2); }
static BitmapContent BitmapConvert(Type bitmapType, Color color, int w, int h) { var b1 = new PixelBitmapContent <Color>(w, h); Fill(b1, color); var b2 = (BitmapContent)Activator.CreateInstance(bitmapType, b1.Width, b1.Height); BitmapContent.Copy(b1, b2); return(b2); }
private List <Glyph> ExtractGlyphs(PixelBitmapContent <Color> bitmap) { var glyphs = new List <Glyph>(); var regions = new List <Rectangle>(); for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { if (bitmap.GetPixel(x, y) != transparentPixel) { // if we don't have a region that has this pixel already var re = regions.Find(r => { return(r.Contains(x, y)); }); if (re == Rectangle.Empty) { // we have found the top, left of a image. // we now need to scan for the 'bounds' int top = y; int bottom = y; int left = x; int right = x; while (bitmap.GetPixel(right, bottom) != transparentPixel) { right++; } while (bitmap.GetPixel(left, bottom) != transparentPixel) { bottom++; } // we got a glyph :) regions.Add(new Rectangle(left, top, right - left, bottom - top)); x = right; } else { x += re.Width; } } } } for (int i = 0; i < regions.Count; i++) { var rect = regions[i]; var newBitmap = new PixelBitmapContent <Color>(rect.Width, rect.Height); BitmapContent.Copy(bitmap, rect, newBitmap, new Rectangle(0, 0, rect.Width, rect.Height)); var glyph = new Glyph(GetCharacterForIndex(i), newBitmap); glyph.CharacterWidths.B = glyph.Bitmap.Width; glyphs.Add(glyph); //newbitmap.Save (GetCharacterForIndex(i)+".png", System.Drawing.Imaging.ImageFormat.Png); } return(glyphs); }
private MipmapChain CreateFace(BitmapContent bitmapContent, int w, int h, int xOffset) { PixelBitmapContent <Color> result; result = new PixelBitmapContent <Color>(w, h); Rectangle sourceRegion = new Rectangle(xOffset, 0, w, h); Rectangle destinationRegion = new Rectangle(0, 0, w, h); BitmapContent.Copy(bitmapContent, sourceRegion, result, destinationRegion); return(result); }
private static void RenderAtlas(TextureAtlasContent output) { var outputBmp = new PixelBitmapContent <Color>(output.Width, output.Height); foreach (var sprite in output.DestinationSprites) { var srcBmp = sprite.Texture.Faces[0][0]; var srcRect = new Rectangle(0, 0, srcBmp.Width, srcBmp.Height); BitmapContent.Copy(srcBmp, srcRect, outputBmp, sprite.Bounds); } var mipmapChain = new MipmapChain(outputBmp); output.Texture.Mipmaps = mipmapChain; }
private static BitmapContent ConvertBitmap(BitmapContent source, Type newType, int width, int height) { BitmapContent content; try { content = (BitmapContent)Activator.CreateInstance(newType, new object[] { width, height }); } catch (TargetInvocationException exception) { throw new Exception(exception.InnerException.Message); } BitmapContent.Copy(source, content); return(content); }
public void BitmapCopyFullResize() { var b1 = new PixelBitmapContent <Color>(8, 8); Fill(b1, Color.Red); var b2 = new PixelBitmapContent <Color>(4, 4); BitmapContent.Copy(b1, b2); for (var y = 0; y < b2.Height; y++) { for (var x = 0; x < b2.Width; x++) { Assert.AreEqual(Color.Red, b2.GetPixel(x, y)); } } }
public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) { // Fallback if we aren't buiding for iOS. var platform = ContentHelper.GetMonoGamePlatform(); if (platform != MonoGamePlatform.iOS) { return(base.Process(input, context)); } SpriteFontContent content = base.Process(input, context); FieldInfo TextureField = typeof(SpriteFontContent).GetField("texture", BindingFlags.Instance | BindingFlags.NonPublic); Texture2DContent texture = (Texture2DContent)TextureField.GetValue(content); // TODO: This is a very lame way of doing this as we're getting compression artifacts twice, but is the quickest way to get // Compressed fonts up and running. The SpriteFontContent/Processor contains a ton // of sealed/internal classes riddled with private fields, so overriding CompressFontTexture // or even Process is tricky. This works for now, but should be replaced when the content pipeline // moves a bit further var texWidth = ContentHelper.NextPOT(texture.Faces[0][0].Width); var texHeight = ContentHelper.NextPOT(texture.Faces[0][0].Height); // Resize to square, power of two if necessary. if (texWidth != texHeight || texture.Faces[0][0].Width != texture.Faces[0][0].Height || texWidth != texture.Faces[0][0].Width || texHeight != texture.Faces[0][0].Height) { texHeight = texWidth = Math.Max(texHeight, texWidth); var resizedBitmap = (BitmapContent)Activator.CreateInstance(typeof(PixelBitmapContent <Color>), new object[] { texWidth, texHeight }); var textureRegion = new Rectangle(0, 0, texture.Faces[0][0].Width, texture.Faces[0][0].Height); BitmapContent.Copy(texture.Faces[0][0], textureRegion, resizedBitmap, textureRegion); texture.Faces[0].Clear(); texture.Faces[0].Add(resizedBitmap); context.Logger.LogImportantMessage(string.Format("Resized font texture {0} to {1}x{2}", input.Name, resizedBitmap.Width, resizedBitmap.Height)); } else { texture.ConvertBitmapType(typeof(PixelBitmapContent <Color>)); } MGTextureProcessor.ConvertToPVRTC(texture, 1, true, MGCompressionMode.PVRTCFourBitsPerPixel); return(content); }
void BitmapCopyFullNoResize <T>(T color1) where T : struct, IEquatable <T> { var b1 = new PixelBitmapContent <T>(8, 8); Fill(b1, color1); var b2 = new PixelBitmapContent <T>(8, 8); BitmapContent.Copy(b1, b2); for (var y = 0; y < b2.Height; y++) { for (var x = 0; x < b2.Width; x++) { Assert.AreEqual(color1, b2.GetPixel(x, y)); } } }
void BitmapCopyFullResize <T>(T color1, IEqualityComparer <T> comparer) where T : struct, IEquatable <T> { var b1 = new PixelBitmapContent <T>(8, 8); Fill(b1, color1); var b2 = new PixelBitmapContent <T>(4, 4); BitmapContent.Copy(b1, b2); for (var y = 0; y < b2.Height; y++) { for (var x = 0; x < b2.Width; x++) { Assert.That(color1, Is.EqualTo(b2.GetPixel(x, y)).Using(comparer)); } } }
/// <summary> /// The four side faces of the cubemap are easy to create: we just copy /// out the appropriate region from the middle of the source bitmap. /// </summary> static BitmapContent CreateSideFace(PixelBitmapContent <Color> source, int cubeSide) { PixelBitmapContent <Color> result; result = new PixelBitmapContent <Color>(cubemapSize, cubemapSize); Rectangle sourceRegion = new Rectangle(source.Width * cubeSide / 4, source.Height / 3, source.Width / 4, source.Height / 3); Rectangle destinationRegion = new Rectangle(0, 0, cubemapSize, cubemapSize); BitmapContent.Copy(source, sourceRegion, result, destinationRegion); return(result); }
public void BitmapCopyRegionResize() { var b1 = new PixelBitmapContent <Color>(8, 8); Fill(b1, Color.Red); var b2 = new PixelBitmapContent <Color>(8, 8); Fill(b2, Color.Blue); BitmapContent.Copy(b1, new Rectangle(0, 0, 4, 4), b2, new Rectangle(0, 0, 3, 6)); for (var y = 0; y < b2.Height; y++) { for (var x = 0; x < b2.Width; x++) { Assert.AreEqual(x < 3 && y < 6 ? Color.Red : Color.Blue, b2.GetPixel(x, y)); } } }
/// <summary> /// Once the arranging is complete, copies the bitmap data for each /// sprite to its chosen position in the single larger output bitmap. /// </summary> static BitmapContent CopySpritesToOutput(List <ArrangedSprite> p_sprites, IList <BitmapContent> p_sourceSprites, ICollection <Rectangle> p_outputSprites, int p_width, int p_height) { BitmapContent l_output = new PixelBitmapContent <Color>(p_width, p_height); foreach (ArrangedSprite l_sprite in p_sprites) { BitmapContent l_source = p_sourceSprites[l_sprite.Index]; int l_x = l_sprite.X; int l_y = l_sprite.Y; int l_width = l_source.Width; int l_height = l_source.Height; // Copy the main sprite data to the output sheet. BitmapContent.Copy(l_source, new Rectangle(0, 0, l_width, l_height), l_output, new Rectangle(l_x + 1, l_y + 1, l_width, l_height)); // Copy a border strip from each edge of the sprite, creating // a one pixel padding area to avoid filtering problems if the // sprite is scaled or rotated. BitmapContent.Copy(l_source, new Rectangle(0, 0, 1, l_height), l_output, new Rectangle(l_x, l_y + 1, 1, l_height)); BitmapContent.Copy(l_source, new Rectangle(l_width - 1, 0, 1, l_height), l_output, new Rectangle(l_x + l_width + 1, l_y + 1, 1, l_height)); BitmapContent.Copy(l_source, new Rectangle(0, 0, l_width, 1), l_output, new Rectangle(l_x + 1, l_y, l_width, 1)); BitmapContent.Copy(l_source, new Rectangle(0, l_height - 1, l_width, 1), l_output, new Rectangle(l_x + 1, l_y + l_height + 1, l_width, 1)); // Copy a single pixel from each corner of the sprite, // filling in the corners of the one pixel padding area. BitmapContent.Copy(l_source, new Rectangle(0, 0, 1, 1), l_output, new Rectangle(l_x, l_y, 1, 1)); BitmapContent.Copy(l_source, new Rectangle(l_width - 1, 0, 1, 1), l_output, new Rectangle(l_x + l_width + 1, l_y, 1, 1)); BitmapContent.Copy(l_source, new Rectangle(0, l_height - 1, 1, 1), l_output, new Rectangle(l_x, l_y + l_height + 1, 1, 1)); BitmapContent.Copy(l_source, new Rectangle(l_width - 1, l_height - 1, 1, 1), l_output, new Rectangle(l_x + l_width + 1, l_y + l_height + 1, 1, 1)); // Remember where we placed this sprite. p_outputSprites.Add(new Rectangle(l_x + 1, l_y + 1, l_width, l_height)); } return(l_output); }
void BitmapCopyMoveRegionNoResize <T>(T color1, T color2) where T : struct, IEquatable <T> { var b1 = new PixelBitmapContent <T>(8, 8); Fill(b1, color1); var b2 = new PixelBitmapContent <T>(8, 8); Fill(b2, color2); BitmapContent.Copy(b1, new Rectangle(0, 0, 4, 4), b2, new Rectangle(4, 4, 4, 4)); for (var y = 0; y < b2.Height; y++) { for (var x = 0; x < b2.Width; x++) { Assert.AreEqual(x >= 4 && y >= 4 ? color1 : color2, b2.GetPixel(x, y)); } } }
void BitmapCopyRegionResize <T>(T color1, T color2, IEqualityComparer <T> comparer) where T : struct, IEquatable <T> { var b1 = new PixelBitmapContent <T>(8, 8); Fill(b1, color1); var b2 = new PixelBitmapContent <T>(8, 8); Fill(b2, color2); BitmapContent.Copy(b1, new Rectangle(0, 0, 4, 4), b2, new Rectangle(0, 0, 3, 6)); for (var y = 0; y < b2.Height; y++) { for (var x = 0; x < b2.Width; x++) { Assert.That(x < 3 && y < 6 ? color1 : color2, Is.EqualTo(b2.GetPixel(x, y)).Using(comparer)); } } }
public void BitmapConvertFullNoResize() { var b1 = new PixelBitmapContent <Color>(8, 8); Fill(b1, Color.Red); var b2 = new PixelBitmapContent <Bgr565>(8, 8); BitmapContent.Copy(b1, b2); var packed = new Bgr565(1.0f, 0.0f, 0.0f); for (var y = 0; y < b2.Height; y++) { for (var x = 0; x < b2.Width; x++) { Assert.AreEqual(packed, b2.GetPixel(x, y)); } } }
public override SpriteFontContent Process(Texture2DContent input, ContentProcessorContext context) { // Fallback if we aren't buiding for iOS. var platform = ContentHelper.GetMonoGamePlatform(); if (platform != MonoGamePlatform.iOS) { return(base.Process(input, context)); } SpriteFontContent content = base.Process(input, context); // TODO: This is a very lame way of doing this as we're getting compression artifacts twice, but is the quickest way to get // Compressed fonts up and running. The SpriteFontContent/Processor contains a ton // of sealed/internal classes riddled with private fields, so overriding CompressFontTexture // or even Process is tricky. This works for now, but should be replaced when the content pipeline // moves a bit further var texWidth = input.Faces[0][0].Width; var texHeight = input.Faces[0][0].Height; // Resize to square, power of two if necessary. if (texWidth != texHeight) { texHeight = texWidth = Math.Max(texHeight, texWidth); var resizedBitmap = (BitmapContent)Activator.CreateInstance(typeof(PixelBitmapContent <Color>), new object[] { texWidth, texHeight }); var textureRegion = new Rectangle(0, 0, input.Faces[0][0].Width, input.Faces[0][0].Height); BitmapContent.Copy(input.Faces[0][0], textureRegion, resizedBitmap, textureRegion); input.Faces[0].Clear(); input.Faces[0].Add(resizedBitmap); } else { input.ConvertBitmapType(typeof(PixelBitmapContent <Color>)); } MGTextureProcessor.ConvertToPVRTC(input, 1, true, MGCompressionMode.PVRTCFourBitsPerPixel); return(content); }
public override TextureContent Process(TextureContent input, ContentProcessorContext context) { var face = input.Faces.First(); var src = face[0]; var columns = src.Width / GridWidth; var rows = src.Height / GridHeight; var dst = new PixelBitmapContent <Color>(src.Width + columns * 2, src.Height + rows * 2); for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++) { var srcRect = new Rectangle { X = c * GridWidth, Y = r * GridHeight, Width = GridWidth, Height = GridHeight }; var dstRect = new Rectangle { X = c * (GridWidth + Padding * 2), Y = r * (GridHeight + Padding * 2), Width = (GridWidth + Padding * 2), Height = (GridHeight + Padding * 2) }; BitmapContent.Copy(src, srcRect, dst, dstRect); dstRect.Inflate(-Padding, -Padding); BitmapContent.Copy(src, srcRect, dst, dstRect); } } face[0] = dst; return(base.Process(input, context)); }
/// <summary> /// The top and bottom cubemap faces will have a nasty discontinuity /// in the middle where the four source image flaps meet. We can cover /// this up by applying a blur filter to the problematic area. /// </summary> static BitmapContent BlurCubemapFace(PixelBitmapContent <Color> source) { // Create two temporary bitmaps. PixelBitmapContent <Vector4> temp1, temp2; temp1 = new PixelBitmapContent <Vector4>(cubemapSize, cubemapSize); temp2 = new PixelBitmapContent <Vector4>(cubemapSize, cubemapSize); // Antialias by shrinking the larger generated image to the final size. BitmapContent.Copy(source, temp1); // Apply the blur in two passes, first horizontally, then vertically. ApplyBlurPass(temp1, temp2, 1, 0); ApplyBlurPass(temp2, temp1, 0, 1); // Convert the result back to Color format. PixelBitmapContent <Color> result; result = new PixelBitmapContent <Color>(cubemapSize, cubemapSize); BitmapContent.Copy(temp1, result); return(result); }
private Texture2DContent CreateContainerTexture(List <KeyValuePair <Texture2DContent, Rectangle> > textures) { BitmapContent output = new PixelBitmapContent <Color>((int)ContainerSize, (int)ContainerSize); foreach (var textureInfo in textures) { BitmapContent texture = textureInfo.Key.Mipmaps[0]; int w = texture.Width; int h = texture.Height; Rectangle texturePosition = textureInfo.Value; int x = texturePosition.X; int y = texturePosition.Y; // Copy the main sprite data to the output sheet BitmapContent.Copy(texture, new Rectangle(0, 0, w, h), output, new Rectangle(x + 1, y + 1, w, h)); // Copy a border strip from each edge of the sprite, creating // a one pixel padding area to avoid filtering problems if the // sprite is scaled or rotated BitmapContent.Copy(texture, new Rectangle(0, 0, 1, h), output, new Rectangle(x, y + 1, 1, h)); BitmapContent.Copy(texture, new Rectangle(w - 1, 0, 1, h), output, new Rectangle(x + w + 1, y + 1, 1, h)); BitmapContent.Copy(texture, new Rectangle(0, 0, w, 1), output, new Rectangle(x + 1, y, w, 1)); BitmapContent.Copy(texture, new Rectangle(0, h - 1, w, 1), output, new Rectangle(x + 1, y + h + 1, w, 1)); // Copy a single pixel from each corner of the sprite, filling in the corners of the one pixel padding area BitmapContent.Copy(texture, new Rectangle(0, 0, 1, 1), output, new Rectangle(x, y, 1, 1)); BitmapContent.Copy(texture, new Rectangle(w - 1, 0, 1, 1), output, new Rectangle(x + w + 1, y, 1, 1)); BitmapContent.Copy(texture, new Rectangle(0, h - 1, 1, 1), output, new Rectangle(x, y + h + 1, 1, 1)); BitmapContent.Copy(texture, new Rectangle(w - 1, h - 1, 1, 1), output, new Rectangle(x + w + 1, y + h + 1, 1, 1)); } Texture2DContent tex2d = new Texture2DContent(); tex2d.Mipmaps = new MipmapChain(output); return(tex2d); }
public override SpriteFontContent Process(Texture2DContent input, ContentProcessorContext context) { // extract the glyphs from the texture and map them to a list of characters. // we need to call GtCharacterForIndex for each glyph in the Texture to // get the char for that glyph, by default we start at ' ' then '!' and then ASCII // after that. BitmapContent face = input.Faces[0][0]; face.TryGetFormat(out SurfaceFormat faceFormat); if (faceFormat != SurfaceFormat.Rgba32) { var colorFace = new PixelBitmapContent <Color>(face.Width, face.Height); BitmapContent.Copy(face, colorFace); face = colorFace; } var output = new SpriteFontContent(); var glyphs = ExtractGlyphs((PixelBitmapContent <Color>)face); // Optimize. foreach (var glyph in glyphs) { GlyphCropper.Crop(glyph); output.VerticalLineSpacing = Math.Max(output.VerticalLineSpacing, glyph.Subrect.Height); } // Get the platform specific texture profile. var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); texProfile.Requirements(context, TextureFormat, out bool requiresPot, out bool requiresSquare); face = GlyphPacker.ArrangeGlyphs(glyphs, requiresPot, requiresSquare); foreach (var glyph in glyphs) { output.CharacterMap.Add(glyph.Character); output.Regions.Add( new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, glyph.Subrect.Height)); output.Croppings.Add( new Rectangle((int)glyph.XOffset, (int)glyph.YOffset, glyph.Width, glyph.Height)); var abc = glyph.CharacterWidths; output.Kerning.Add(new Vector3(abc.A, abc.B, abc.C)); } output.Texture.Faces[0].Add(face); var bmp = output.Texture.Faces[0][0]; if (PremultiplyAlpha) { var data = bmp.GetPixelData(); var idx = 0; for (; idx < data.Length;) { var r = data[idx + 0]; var g = data[idx + 1]; var b = data[idx + 2]; var a = data[idx + 3]; var col = Color.FromNonPremultiplied(r, g, b, a); data[idx + 0] = col.R; data[idx + 1] = col.G; data[idx + 2] = col.B; data[idx + 3] = col.A; idx += 4; } bmp.SetPixelData(data); } // Perform the final texture conversion. texProfile.ConvertTexture(context, output.Texture, TextureFormat, true); return(output); }
public TextureAtlasContent Process(TextureAtlasContent input, ContentProcessorContext context) { if (MipmapsPerSprite && GenerateMipmaps) { foreach (var texture in input.Textures) { texture.Texture.GenerateMipmaps(false); } } var output = input; if (GenerateMipmaps) { if (MipmapsPerSprite) { var maxSpriteWidth = 1; var maxSpriteHeight = 1; foreach (var sprite in input.Textures) { var face0 = sprite.Texture.Faces[0]; maxSpriteWidth = Math.Max(maxSpriteWidth, face0[0].Width); maxSpriteHeight = Math.Max(maxSpriteHeight, face0[0].Height); } for (int mipLevel = 1; ; mipLevel++) { int mipLevel2 = (int)Math.Pow(2, mipLevel); Rectangle size = new Rectangle(0, 0, input.Width, input.Height); size.Width /= mipLevel2; size.Height /= mipLevel2; if ((maxSpriteWidth / mipLevel2) < 1 && (maxSpriteHeight / mipLevel2) < 1) { break; } var mipmapBmp = new PixelBitmapContent <Color>(size.Width, size.Height); foreach (var sprite in input.Sprites) { if (mipLevel >= sprite.Texture.Faces[0].Count) { continue; } var srcBmp = sprite.Texture.Faces[0][mipLevel]; var srcRect = new Rectangle(0, 0, srcBmp.Width, srcBmp.Height); var destRect = sprite.DestinationRectangle; destRect.X = (int)Math.Ceiling((float)destRect.X / mipLevel2); destRect.Y = (int)Math.Ceiling((float)destRect.Y / mipLevel2); destRect.Width = (int)(destRect.Width / mipLevel2); destRect.Height = (int)(destRect.Height / mipLevel2); if (destRect.Width > 1 && destRect.Height > 1) { BitmapContent.Copy(srcBmp, srcRect, mipmapBmp, destRect); } } output.Mipmaps.Add(mipmapBmp); } var outputFace0 = output.Faces[0]; while (outputFace0[outputFace0.Count - 1].Width > 1 || outputFace0[outputFace0.Count - 1].Height > 1) { var lastMipmap = outputFace0[outputFace0.Count - 1]; var w = Math.Max(1, lastMipmap.Width / 2); var h = Math.Max(1, lastMipmap.Height / 2); var mipmapBmp = new PixelBitmapContent <Color>(w, h); //PixelBitmapContent<Color>.Copy(lastMipmap, mipmapBmp); output.Mipmaps.Add(mipmapBmp); } } else { output.GenerateMipmaps(false); } } base.Process(output, context); return(output); }
public override TextureContent Process(TextureContent input, ContentProcessorContext context) { SurfaceFormat format; if (input.Faces[0][0].TryGetFormat(out format)) { // If it is already a compressed format, we cannot do anything else so just return it if (format.IsCompressedFormat()) { return(input); } } if (ColorKeyEnabled || ResizeToPowerOfTwo || MakeSquare || PremultiplyAlpha) { // Convert to floating point format for modifications. Keep the original format for conversion back later on if required. var originalType = input.Faces[0][0].GetType(); try { input.ConvertBitmapType(typeof(PixelBitmapContent <Vector4>)); } catch (Exception ex) { context.Logger.LogImportantMessage("Could not convert input texture for processing. " + ex.ToString()); throw ex; } for (int f = 0; f < input.Faces.Count; ++f) { var face = input.Faces[f]; for (int m = 0; m < face.Count; ++m) { var bmp = (PixelBitmapContent <Vector4>)face[m]; if (ColorKeyEnabled) { bmp.ReplaceColor(ColorKeyColor.ToVector4(), Vector4.Zero); } if (ResizeToPowerOfTwo) { if (!GraphicsUtil.IsPowerOfTwo(bmp.Width) || !GraphicsUtil.IsPowerOfTwo(bmp.Height) || (MakeSquare && bmp.Height != bmp.Width)) { var newWidth = GraphicsUtil.GetNextPowerOfTwo(bmp.Width); var newHeight = GraphicsUtil.GetNextPowerOfTwo(bmp.Height); if (MakeSquare) { newWidth = newHeight = Math.Max(newWidth, newHeight); } var resized = new PixelBitmapContent <Vector4>(newWidth, newHeight); BitmapContent.Copy(bmp, resized); bmp = resized; } } else if (MakeSquare && bmp.Height != bmp.Width) { var newSize = Math.Max(bmp.Width, bmp.Height); var resized = new PixelBitmapContent <Vector4>(newSize, newSize); BitmapContent.Copy(bmp, resized); } if (PremultiplyAlpha) { for (int y = 0; y < bmp.Height; ++y) { var row = bmp.GetRow(y); for (int x = 0; x < bmp.Width; ++x) { row[x] = Color.FromNonPremultiplied(row[x]).ToVector4(); } } } face[m] = bmp; } } // If no change to the surface format was desired, change it back now before it early outs if (TextureFormat == TextureProcessorOutputFormat.NoChange) { input.ConvertBitmapType(originalType); } } // Get the texture profile for the platform and let it convert the texture. var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); texProfile.ConvertTexture(context, input, TextureFormat, GenerateMipmaps, false); return(input); }
public override SpriteFontContent Process(Texture2DContent input, ContentProcessorContext context) { var output = new SpriteFontContent(); // extract the glyphs from the texture and map them to a list of characters. // we need to call GtCharacterForIndex for each glyph in the Texture to // get the char for that glyph, by default we start at ' ' then '!' and then ASCII // after that. BitmapContent face = input.Faces[0][0]; SurfaceFormat faceFormat; face.TryGetFormat(out faceFormat); if (faceFormat != SurfaceFormat.Color) { var colorFace = new PixelBitmapContent <Color>(face.Width, face.Height); BitmapContent.Copy(face, colorFace); face = colorFace; } var glyphs = ExtractGlyphs((PixelBitmapContent <Color>)face); // Optimize. foreach (var glyph in glyphs) { GlyphCropper.Crop(glyph); output.VerticalLineSpacing = Math.Max(output.VerticalLineSpacing, glyph.Subrect.Height); } var format = GraphicsUtil.GetTextureFormatForPlatform(TextureFormat, context.TargetPlatform); var requiresPOT = GraphicsUtil.RequiresPowerOfTwo(format, context.TargetPlatform, context.TargetProfile); var requiresSquare = GraphicsUtil.RequiresSquare(format, context.TargetPlatform); face = GlyphPacker.ArrangeGlyphs(glyphs.ToArray(), requiresPOT, requiresSquare); foreach (var glyph in glyphs) { output.CharacterMap.Add(glyph.Character); output.Glyphs.Add(new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, glyph.Subrect.Height)); output.Cropping.Add(new Rectangle((int)glyph.XOffset, (int)glyph.YOffset, glyph.Width, glyph.Height)); var abc = glyph.CharacterWidths; output.Kerning.Add(new Vector3(abc.A, abc.B, abc.C)); } output.Texture.Faces[0].Add(face); var bmp = output.Texture.Faces[0][0]; if (PremultiplyAlpha) { var data = bmp.GetPixelData(); var idx = 0; for (; idx < data.Length;) { var r = data[idx + 0]; var g = data[idx + 1]; var b = data[idx + 2]; var a = data[idx + 3]; var col = Color.FromNonPremultiplied(r, g, b, a); data[idx + 0] = col.R; data[idx + 1] = col.G; data[idx + 2] = col.B; data[idx + 3] = col.A; idx += 4; } bmp.SetPixelData(data); } if (GraphicsUtil.IsCompressedTextureFormat(format)) { try { GraphicsUtil.CompressTexture(context.TargetProfile, output.Texture, format, context, false, true); } catch (Exception ex) { context.Logger.LogImportantMessage("{0}", ex.ToString()); } } return(output); }
/// <summary> /// locates the black pixels from a nine patch image and sets the splits for this image /// </summary> /// <param name="texture">Texture.</param> int[] ProcessNinePatchTexture(TextureContent texture) { // left, right, top, bottom of nine patch splits var splits = new int[4]; var bitmap = texture.Faces[0][0]; var data = bitmap.GetPixelData(); var padStart = -1; var padEnd = int.MinValue; for (var x = 0; x < bitmap.Width * 4; x += 4) { // we only care about alpha so disregard r/g/b var alpha = data[x + 3]; if (alpha == 255) { if (padStart == -1) { padStart = x / 4; } else { padEnd = Math.Max(padEnd, x / 4); } } } splits[0] = padStart; splits[1] = bitmap.Width - padEnd; padStart = -1; padEnd = int.MinValue; var rowStride = bitmap.Width * 4; for (var y = 0; y < bitmap.Height * 4; y += 4) { var pixel = (y / 4) * rowStride; // we only care about alpha so disregard r/g/b var alpha = data[pixel + 3]; if (alpha == 255) { if (padStart == -1) { padStart = y / 4; } else { padEnd = Math.Max(padEnd, y / 4); } } } splits[2] = padStart; splits[3] = bitmap.Height - padEnd; Logger.LogMessage("\tnine patch details. l: {0}, r: {1}, t: {2}, b: {3}", splits[0], splits[1], splits[2], splits[3]); // copy the data to a new Bitmap excluding the outside 1 pixel border var output = new PixelBitmapContent <Color>(bitmap.Width - 2, bitmap.Height - 2); BitmapContent.Copy(bitmap, new Rectangle(1, 1, output.Width, output.Height), output, new Rectangle(0, 0, output.Width, output.Height)); texture.Faces[0][0] = output; return(splits); }
public override TextureContent Process(TextureContent input, ContentProcessorContext context) { if (input.Faces[0][0].TryGetFormat(out SurfaceFormat format)) { // If it is already a compressed format, we cannot do anything else so just return it if (format.IsCompressedFormat()) { return(input); } } if (ColorKeyEnabled || ResizeToPowerOfTwo || MakeSquare || PremultiplyAlpha || GenerateMipmaps) { // Convert to floating point format for modifications. Keep the original format for conversion back later on if required. var originalType = input.Faces[0][0].GetType(); try { input.ConvertBitmapType(typeof(PixelBitmapContent <RgbaVector>)); } catch (Exception ex) { context.Logger.LogImportantMessage("Could not convert input texture for processing. " + ex.ToString()); throw; } if (GenerateMipmaps) { input.GenerateMipmaps(true); } for (int f = 0; f < input.Faces.Count; ++f) { var face = input.Faces[f]; for (int m = 0; m < face.Count; ++m) { var bmp = (PixelBitmapContent <RgbaVector>)face[m]; if (ColorKeyEnabled) { var original = new RgbaVector(); // TODO: UNsafe.SkipInit original.FromScaledVector(ColorKeyColor.ToScaledVector4()); bmp.ReplaceColor(original, new RgbaVector(0, 0, 0, 0)); } if (ResizeToPowerOfTwo) { if (!GraphicsUtil.IsPowerOfTwo(bmp.Width) || !GraphicsUtil.IsPowerOfTwo(bmp.Height) || (MakeSquare && bmp.Height != bmp.Width)) { var newWidth = GraphicsUtil.GetNextPowerOfTwo(bmp.Width); var newHeight = GraphicsUtil.GetNextPowerOfTwo(bmp.Height); if (MakeSquare) { newWidth = newHeight = Math.Max(newWidth, newHeight); } var resized = new PixelBitmapContent <RgbaVector>(newWidth, newHeight); BitmapContent.Copy(bmp, resized); bmp = resized; } } else if (MakeSquare && bmp.Height != bmp.Width) { var newSize = Math.Max(bmp.Width, bmp.Height); var resized = new PixelBitmapContent <RgbaVector>(newSize, newSize); BitmapContent.Copy(bmp, resized); } if (PremultiplyAlpha) { var pixels = bmp.GetPixelSpan(); for (int i = 0; i < pixels.Length; i++) { ref RgbaVector pixel = ref pixels[i]; pixel.R *= pixel.A; pixel.G *= pixel.A; pixel.B *= pixel.A; } } face[m] = bmp; } } // If no change to the surface format was desired, change it back now before it early outs if (TextureFormat == TextureProcessorOutputFormat.NoChange) { input.ConvertBitmapType(originalType); } }