/// <summary> /// This function encodes a new texture based on the list of key frame matrices /// </summary> /// <param name="keyFrameMatrices"></param> /// <returns></returns> static private PixelBitmapContent <Vector4> GetEncodedTexture(List <Matrix[]> keyFrameMatrices, int bones) { //We need 4 pixels per bone. We can store each row of the transform matrix in one pixel. int width = bones * 4; //Create a new bitmap content object PixelBitmapContent <Vector4> animationTexture = new PixelBitmapContent <Vector4>(width, keyFrameMatrices.Count); int y = 0; //Now, we'll write all the rows foreach (Matrix[] animationRow in keyFrameMatrices) { int x = 0; foreach (Matrix transform in animationRow) { // Pretty trivial - we just right out the matrix data as pixels. Instead of R, G, B, and A, we write matrix values. // However, as mentioned in the article, this could be optimized. We really only need 3 pixels to describe a matrix, // because in a transform matrix, the fourth row is always (0, 0, 0, 1). Thus, we could use the RGB values to describe the 3x3 // matrix, and then use the A values to describe the translation values in the 4th column. During runtime, this would save // us a vertex texture fetch per transform! animationTexture.SetPixel(x + 0, y, new Vector4(transform.M11, transform.M12, transform.M13, transform.M14)); animationTexture.SetPixel(x + 1, y, new Vector4(transform.M21, transform.M22, transform.M23, transform.M24)); animationTexture.SetPixel(x + 2, y, new Vector4(transform.M31, transform.M32, transform.M33, transform.M34)); animationTexture.SetPixel(x + 3, y, new Vector4(transform.M41, transform.M42, transform.M43, transform.M44)); x += 4; } y++; } return(animationTexture); }
public void ColorKey() { var context = new TestProcessorContext(TargetPlatform.Windows, "dummy.xnb"); var processor = new TextureProcessor { ColorKeyColor = Color.Red, ColorKeyEnabled = true, GenerateMipmaps = false, PremultiplyAlpha = false, ResizeToPowerOfTwo = false, TextureFormat = TextureProcessorOutputFormat.Color }; var face = new PixelBitmapContent<Color>(8, 8); Fill(face, Color.Red); var input = new Texture2DContent(); input.Faces[0] = face; var output = processor.Process(input, context); Assert.NotNull(output); Assert.AreEqual(1, output.Faces.Count); Assert.AreEqual(1, output.Faces[0].Count); Assert.IsAssignableFrom<PixelBitmapContent<Color>>(output.Faces[0][0]); var outFace = (PixelBitmapContent<Color>)output.Faces[0][0]; Assert.AreEqual(8, outFace.Width); Assert.AreEqual(8, outFace.Height); for (var y=0; y < outFace.Height; y++) for (var x = 0; x < outFace.Width; x++) Assert.AreEqual(Color.Transparent, outFace.GetPixel(x, y)); }
/// <summary> /// Applies a single pass of a separable box filter, blurring either /// along the x or y axis. This could give much higher quality results /// if we used a gaussian filter kernel rather than this simplistic box, /// but this is good enough to get the job done. /// </summary> static void ApplyBlurPass(PixelBitmapContent <Vector4> source, PixelBitmapContent <Vector4> destination, int dx, int dy) { int cubemapCenter = cubemapSize / 2; for (int y = 0; y < cubemapSize; y++) { for (int x = 0; x < cubemapSize; x++) { // How far is this texel from the center of the image? int xDist = cubemapCenter - x; int yDist = cubemapCenter - y; int distance = (int)Math.Sqrt(xDist * xDist + yDist * yDist); // Blur more in the center, less near the edges. int blurAmount = Math.Max(cubemapCenter - distance, 0) / 8; // Accumulate source texel values. Vector4 blurredValue = Vector4.Zero; for (int i = -blurAmount; i <= blurAmount; i++) { blurredValue += source.GetPixel(x + dx * i, y + dy * i); } // Average them to calculate a blurred result. blurredValue /= blurAmount * 2 + 1; destination.SetPixel(x, y, blurredValue); } } }
public override TOutput Process(TInput input, ContentProcessorContext context) { input.ConvertBitmapType(typeof(PixelBitmapContent <Vector4>)); PixelBitmapContent <Vector4> bm = (PixelBitmapContent <Vector4>)(((Texture2DContent)input).Mipmaps[0]); for (int y = 0, ym = bm.Height; y != ym; ++y) { for (int x = 0, xm = bm.Width; x != xm; ++x) { Vector4 v = bm.GetPixel(x, y); float w = 1 - v.W; if (v.Z > w) { v.Z = w; } w -= v.Z; if (v.Y > w) { v.Y = w; } w -= v.Y; if (v.X > w) { v.X = w; } System.Diagnostics.Debug.Assert(v.X + v.Y + v.Z + v.W <= 1.001f); // it's OK for w to be > 0 here, as that means the base layer weight bm.SetPixel(x, y, v); } } input.ConvertBitmapType(typeof(PixelBitmapContent <Color>)); input.GenerateMipmaps(true); return(input); }
/// <summary> /// 指定された単色ビットマップ画像をDXT3テクスチャへ変換する /// </summary> /// <param name="source">変換元画像</param> /// <param name="color0">単色カラー</param> /// <returns>DXT3圧縮された画像</returns> public static Dxt3BitmapContent Compress(PixelBitmapContent<Color> source, Color color0) { // DXT3ブロックデータを格納するためのバッファを確保 byte[] outputData = new byte[source.Width * source.Height]; // 単色カラーをBGR565に変換する ushort packedColor = new Bgr565(color0.ToVector3()).PackedValue; // 指定された画像を圧縮ブロック単位に処理をする int outputIndex = 0; for (int blockY = 0; blockY < source.Height; blockY += 4) { for (int blockX = 0; blockX < source.Width; blockX += 4) { CompressDxt3Block(source, blockX, blockY, packedColor, outputData, outputIndex); outputIndex += 16; } } // DXT3テクスチャの生成と圧縮したブロックデータの設定 var result = new Dxt3BitmapContent(source.Width, source.Height); result.SetPixelData(outputData); return result; }
protected string BuildTexture(Color color, IDictionary <string, object> processorParameters = null) { PixelBitmapContent <Color> bitmap = new PixelBitmapContent <Color>(1, 1); bitmap.SetPixel(0, 0, color); return(BuildTexture(bitmap, processorParameters)); }
/// <summary> /// 指定された単色ビットマップ画像をDXT3テクスチャへ変換する /// </summary> /// <param name="source">変換元画像</param> /// <param name="color0">単色カラー</param> /// <returns>DXT3圧縮された画像</returns> public static Dxt3BitmapContent Compress(PixelBitmapContent <Color> source, Color color0) { // DXT3ブロックデータを格納するためのバッファを確保 byte[] outputData = new byte[source.Width * source.Height]; // 単色カラーをBGR565に変換する ushort packedColor = new Bgr565(color0.ToVector3()).PackedValue; // 指定された画像を圧縮ブロック単位に処理をする int outputIndex = 0; for (int blockY = 0; blockY < source.Height; blockY += 4) { for (int blockX = 0; blockX < source.Width; blockX += 4) { CompressDxt3Block(source, blockX, blockY, packedColor, outputData, outputIndex); outputIndex += 16; } } // DXT3テクスチャの生成と圧縮したブロックデータの設定 var result = new Dxt3BitmapContent(source.Width, source.Height); result.SetPixelData(outputData); return(result); }
void CompressDefault <T>(TargetPlatform platform, Color color, int width = 16, int height = 16) { var context = new TestProcessorContext(platform, "dummy.xnb"); var processor = new TextureProcessor { ColorKeyEnabled = false, GenerateMipmaps = true, PremultiplyAlpha = false, ResizeToPowerOfTwo = false, TextureFormat = TextureProcessorOutputFormat.Compressed }; var face = new PixelBitmapContent <Color>(width, height); Fill(face, color); var input = new Texture2DContent(); input.Faces[0] = face; var output = processor.Process(input, context); Assert.NotNull(output); Assert.AreEqual(1, output.Faces.Count, "Expected number of faces"); Assert.AreEqual(5, output.Faces[0].Count, "Expected number of mipmaps"); Assert.IsAssignableFrom <T>(output.Faces[0][0], "Incorrect pixel format"); }
void CompressDefault <T>(TargetPlatform platform, Color color) { var context = new TestProcessorContext(platform, "dummy.xnb"); var processor = new TextureProcessor { ColorKeyEnabled = false, GenerateMipmaps = false, PremultiplyAlpha = false, ResizeToPowerOfTwo = false, TextureFormat = TextureProcessorOutputFormat.Compressed }; var face = new PixelBitmapContent <Color>(16, 16); Fill(face, color); var input = new Texture2DContent(); input.Faces[0] = face; var output = processor.Process(input, context); Assert.NotNull(output); Assert.AreEqual(1, output.Faces.Count); Assert.AreEqual(1, output.Faces[0].Count); Assert.IsAssignableFrom <T>(output.Faces[0][0]); }
public override Texture2DContent Import(string filename, ContentImporterContext context) { // Load Arena2Path.txt arena2Path = File.ReadAllText( Path.Combine(Path.GetDirectoryName(filename), Arena2PathTxt)); // Read input text string input = File.ReadAllText(filename); // Remove new lines input = input.Replace('\n', ' ').Trim(); input = input.Replace('\r', ' ').Trim(); // Get source information string[] lines = input.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); string textureFilename = lines[0].Trim(); int record = Convert.ToInt32(lines[1].Trim()); int frame = Convert.ToInt32(lines[2].Trim()); // Get bitmap in RGBA format ImageFileReader fileReader = new ImageFileReader(arena2Path); DFImageFile imageFile = fileReader.LoadFile(textureFilename); DFBitmap dfBitmap = imageFile.GetBitmapFormat(record, frame, 0, DFBitmap.Formats.RGBA); // Set bitmap data BitmapContent bitmapContent = new PixelBitmapContent <Color>(dfBitmap.Width, dfBitmap.Height); bitmapContent.SetPixelData(dfBitmap.Data); Texture2DContent tc = new Texture2DContent(); tc.Faces[0] = bitmapContent; return(tc); }
/// <summary> /// Using height data stored in the alpha channel, computes normalmap /// vectors and stores them in the RGB portion of the bitmap. /// </summary> static void ConvertAlphaToNormals(PixelBitmapContent <Vector4> bitmap) { for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { // Look up the heights to either side of this pixel. float left = GetHeight(bitmap, x - 1, y); float right = GetHeight(bitmap, x + 1, y); float top = GetHeight(bitmap, x, y - 1); float bottom = GetHeight(bitmap, x, y + 1); // Compute gradient vectors, then cross them to get the normal. Vector3 dx = new Vector3(1, 0, (right - left) * bumpSize); Vector3 dy = new Vector3(0, 1, (bottom - top) * bumpSize); Vector3 normal = Vector3.Cross(dx, dy); normal.Normalize(); // Store the result. float alpha = GetHeight(bitmap, x, y); bitmap.SetPixel(x, y, new Vector4(normal, alpha)); } } }
/// <summary> /// Process converts the encoded normals to the NormalizedByte4 format and /// generates mipmaps. /// </summary> /// <param name="input"></param> /// <param name="context"></param> /// <returns></returns> public override TextureContent Process(TextureContent input, ContentProcessorContext context) { Texture2DContent result = new Texture2DContent(); if (input.Faces[0][0] is PixelBitmapContent <Alpha8> ) { return(input); } input.ConvertBitmapType(typeof(PixelBitmapContent <Vector3>)); PixelBitmapContent <Vector3> source = input.Faces[0][0] as PixelBitmapContent <Vector3>; PixelBitmapContent <Alpha8> bitmap = new PixelBitmapContent <Alpha8>(source.Width, source.Height); for (int y = 0; y < source.Height; ++y) { for (int x = 0; x < source.Width; ++x) { Vector3 src = source.GetPixel(x, y); bitmap.SetPixel(x, y, new Alpha8( 0.3f * src.X + 0.59f * src.Y + 0.11f * src.Z)); } } result.Mipmaps.Add(bitmap); return(result); }
public void BitmapCompressFullResize() { var b1 = new PixelBitmapContent<Color>(16, 16); Fill(b1, Color.Red); var b2 = new Dxt1BitmapContent(8, 8); BitmapContent.Copy(b1, b2); }
static PixelBitmapContent <Color> CreateAlphaChannel(PixelBitmapContent <Color> input) { int width = input.Width; int height = input.Height; PixelBitmapContent <Color> result = new PixelBitmapContent <Color>(width, height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Color color = input.GetPixel(x, y); // Adds/Replaces Alpha channel with the "Brightest color channel value // A better way would be to average all three colors and use that for alpha. // This will work just fine for grey scale textures and is simpler... byte resultAlpha1 = (byte)(color.PackedValue & 0xff); byte resultAlpha2 = (byte)(color.PackedValue & 0xff00); byte resultAlpha3 = (byte)(color.PackedValue & 0xff0000); byte resultAlpha = Math.Max(Math.Max(resultAlpha1, resultAlpha2), resultAlpha3); color.PackedValue = (uint)(resultAlpha << 24) + (0x00ffffff); result.SetPixel(x, y, color); } } return(result); }
public override Vertices Process(Texture2DContent input, ContentProcessorContext context) { if (ScaleFactor < 1) { throw new Exception("Pixel to meter ratio must be greater than zero."); } PixelBitmapContent <Color> bitmapContent = (PixelBitmapContent <Color>)input.Faces[0][0]; uint[] colorData = new uint[bitmapContent.Width * bitmapContent.Height]; for (int i = 0; i < bitmapContent.Height; i++) { for (int j = 0; j < bitmapContent.Width; j++) { Color c = bitmapContent.GetPixel(j, i); c.R *= c.A; c.G *= c.A; c.B *= c.A; colorData[i * bitmapContent.Width + j] = c.PackedValue; } } Vertices outline = PolygonUtils.CreatePolygon(colorData, bitmapContent.Width, HoleDetection); Vector2 centroid = -outline.GetCentroid(); outline.Translate(ref centroid); Vector2 scale = new Vector2(_scaleFactor); outline.Scale(ref scale); return(outline); }
/// <summary> /// Called by the XNA Framework when importing a texture file to be used as a game asset. This is the method called by the XNA Framework when an asset is to be imported into an object that can be recognized by the Content Pipeline. /// </summary> /// <param name="filename">Name of a game asset file.</param> /// <param name="context">Contains information for importing a game asset, such as a logger interface.</param> /// <returns>Resulting game asset.</returns> public override TextureContent Import(string filename, ContentImporterContext context) { var output = new Texture2DContent(); output._bitmap = new Bitmap(filename); var width = output._bitmap.Width; var height = output._bitmap.Height; // Force the input's pixelformat to ARGB32, so we can have a common pixel format to deal with. if (output._bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb) { var bitmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); using (var graphics = System.Drawing.Graphics.FromImage(bitmap)) { graphics.DrawImage(output._bitmap, 0, 0, width, height); } output._bitmap = bitmap; } var imageData = output._bitmap.GetData(); var bitmapContent = new PixelBitmapContent <Color>(width, height); bitmapContent.SetPixelData(imageData); output.Faces.Add(new MipmapChain(bitmapContent)); return(output); }
private AbstractTile ParseTileNode(XmlNode tileNode, LevelSet project, Dictionary <int, object> objectIdDictionary) { SimpleTile2DTransitionObject tile = new SimpleTile2DTransitionObject(); tile.Name = tileNode.Attributes["name"].Value; int id = Convert.ToInt32(tileNode.Attributes["id"].Value); int height = Convert.ToInt32(tileNode.Attributes["height"].Value); int width = Convert.ToInt32(tileNode.Attributes["width"].Value); objectIdDictionary[id] = tile; Texture2DContent textureContent = new Texture2DContent(); foreach (XmlNode childNode in tileNode.ChildNodes) { if (childNode.Name == "contents") { byte[] binaryData = Convert.FromBase64String(childNode.InnerText); PixelBitmapContent <Color> rawData = new PixelBitmapContent <Color>(width, height); rawData.SetPixelData(binaryData); textureContent.Mipmaps = new MipmapChain(rawData); } } tile.TextureContent = textureContent; return(tile); }
/// <summary> /// Generates a terrain mesh from an input heightfield texture. /// </summary> public override TerrainModelContent Process(Texture2DContent input, ContentProcessorContext context) { Texture2DContent texture = context.Convert <Texture2DContent, Texture2DContent>(input, "FloatingPointTextureProcessor"); PixelBitmapContent <float> heightfield = (PixelBitmapContent <float>)texture.Mipmaps[0]; float[,] heights = new float[heightfield.Width, heightfield.Height]; for (int y = 0; y < heightfield.Height; y++) { for (int x = 0; x < heightfield.Width; x++) { heights[x, y] = heightfield.GetPixel(x, y); } } HeightMapContent heightMap = new HeightMapContent(heightfield.Width, heightfield.Height, heights, VerticalScale, HorizontalScale); string directory = Path.GetDirectoryName(input.Identity.SourceFilename); string texture1 = Path.Combine(directory, ColorTexture); string texture2 = Path.Combine(directory, DetailTexture); // Create a material, and point it at our terrain texture. DualTextureMaterialContent material = new DualTextureMaterialContent { Texture = context.BuildAsset <TextureContent, TextureContent>(new ExternalReference <TextureContent>(texture1), null), Texture2 = context.BuildAsset <TextureContent, TextureContent>(new ExternalReference <TextureContent>(texture2), null), }; TerrainModelContentBuilder terrainModelContentBuilder = new TerrainModelContentBuilder(PatchSize, Tau, heightMap, material, DetailTextureTiling, HorizontalScale); return(terrainModelContentBuilder.Build(context)); }
public override TextureContent Import(string filename, ContentImporterContext context) { // load tiff data m_pReader = new BinaryReader(File.OpenRead(filename)); int nOffsetFirstIFD = ReadHeader(); ReadAllIfds(nOffsetFirstIFD); m_pReader.Close(); // import into standard XNA bitmap container PixelBitmapContent <float> bitmapContent = new PixelBitmapContent <float>(m_nWidth, m_nHeight); for (int y = 0; y < m_nHeight; y++) { for (int x = 0; x < m_nWidth; x++) { bitmapContent.SetPixel(x, y, m_pImageData[(y * m_nWidth) + x]); } } // create and return one-mipmap-level Texture2DContent content = new Texture2DContent(); content.Mipmaps.Add(bitmapContent); return(content); }
protected virtual void BuildNormalMap(PixelBitmapContent <Single> bm, PixelBitmapContent <Color> n) { unchecked { int ww = n.Width; int hh = n.Height; for (int y = 0; y < hh; ++y) { for (int x = 0; x < ww; ++x) { float v00 = bm.GetPixel(x, y); float v01 = bm.GetPixel(x, y + 1); float v10 = bm.GetPixel(x + 1, y); float v11 = bm.GetPixel(x + 1, y + 1); // 80 meters up/down for the renderer // two dx-es means divide by 2 (to average) // two meters per triangle side means divide by 2 to normalize to meters // That is crappy resolution. I should probably use floats instead of bytes // for the underlying storage pixmap... float ddx = (v10 + v11 - v00 - v01) * Page.DynamicRange * 0.5f * 0.5f; float ddy = (v01 + v11 - v00 - v10) * Page.DynamicRange * 0.5f * 0.5f; Vector3 v = new Vector3(-ddx, -ddy, 1.0f); v.Normalize(); v = v * 0.5f + new Vector3(0.5f, 0.5f, 0.5f); Color c = new Color(v); n.SetPixel(x, y, c); } } } }
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); }
/// <summary> /// Flattens vectors from a normal map into a 2D displacement map /// and stores them in the RG portion of the bitmap. /// </summary> public static void ConvertNormalsToDisplacement( PixelBitmapContent <NormalizedByte4> bitmap, float distortionScale) { for (int y = 0; y < bitmap.Height; y++) { for (int x = 0; x < bitmap.Width; x++) { // Get the normal from the normal map Vector4 normal4 = bitmap.GetPixel(x, y).ToVector4(); Vector3 normal3 = new Vector3(normal4.X, normal4.Y, normal4.Z); // Determine the magnitude of the distortion at this pixel float amount = Vector3.Dot(normal3, Vector3.Backward) * distortionScale; // Create a displacement vector of that magnitude in the direction // of the normal projected onto the plane of the texture. Vector2 normal2 = new Vector2(normal3.X, normal3.Y); Vector2 displacement = normal2 * amount + new Vector2(.5f, .5f); // Store the result bitmap.SetPixel(x, y, new NormalizedByte4(displacement.X, displacement.Y, 0, 0)); } } }
unsafe private static BitmapContent ConvertToColor(BitmapContent input) { var width = input.Width; var height = input.Height; SurfaceFormat format; input.TryGetFormat(out format); var formatSize = DDSImporter.GetBitmapSize(format, width, height); var blocks = formatSize; var inData = input.GetPixelData(); var output = new PixelBitmapContent <Color>(width, height); fixed(byte *p = &inData[0]) { DXT1Block *block = (DXT1Block *)p; //convert DXT1 to color for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int blockIdx = (x / 4) + (y / 4) * (width / 4); int colorIndex = x % 4 + (y % 4) * 4; Color color = block[blockIdx].GetColor(colorIndex); output.SetPixel(x, y, color); } } } return(output); }
public override TextureContent Import(string filename, ContentImporterContext context) { // load raw data FileStream reader = File.OpenRead(filename); int width = 257; int height = 257; byte[] bytes = new byte[reader.Length]; reader.Read(bytes, 0, bytes.Length); reader.Close(); // import into standard XNA bitmap container PixelBitmapContent <Color> bitmapContent = new PixelBitmapContent <Color>(width, height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { bitmapContent.SetPixel(x, y, new Color(bytes[(y * width) + x], 0, 0)); } } // create and return one-mipmap-level Texture2DContent content = new Texture2DContent { Identity = new ContentIdentity(filename) }; content.Mipmaps.Add(bitmapContent); return(content); }
private static void Fill(PixelBitmapContent<Color> content, Color color) { var src = Enumerable.Repeat(color.PackedValue, content.Width * content.Height).ToArray(); var dest = new byte[Marshal.SizeOf(typeof(Color)) * content.Width * content.Height]; Buffer.BlockCopy(src, 0, dest, 0, dest.Length); content.SetPixelData(dest); }
public override Texture2DContent Process(List <byte[]> input, ContentProcessorContext context) { for (int p = 0; p < input.Count; ++p) { if (input[p].Length != Height * Width * sizeof(float) * 3 / (1 << (2 * p))) { throw new InvalidContentException("The number of bytes in one or more of the images does not correlate with the product of the Height and Width properties."); } } MipmapChain imageChain = new MipmapChain(); int mip = 0; for (; mip < input.Count; ++mip) { byte[] paddedBytes = new byte[input[mip].Length / 3 * 4]; int srcIndex = 0; int destIndex = 0; while (srcIndex < input[mip].Length) { paddedBytes[destIndex++] = input[mip][srcIndex++]; if (srcIndex % 12 == 0) { for (int x = 0; x < 4; ++x) { paddedBytes[destIndex++] = 0; } } } int mipReduction = 1 << mip; BitmapContent image = new PixelBitmapContent <Vector4>(Width / mipReduction, Height / mipReduction); image.SetPixelData(paddedBytes); imageChain.Add(image); } // Check to see if this is a partial mipmap chain: if (imageChain.Count > 1) { // Just fill the rest of the chain with anything to satisfy the validator that the chain is complete. while ((Math.Max(Height, Width) >> (mip - 1)) > 1) { int mipReduction = 1 << mip; int mipHeight = Math.Max(Height / mipReduction, 1); int mipWidth = Math.Max(Width / mipReduction, 1); byte[] bytes = new byte[mipHeight * mipWidth * sizeof(float) * 4]; BitmapContent image = new PixelBitmapContent <Vector4>(mipWidth, mipHeight); image.SetPixelData(bytes); imageChain.Add(image); ++mip; } } Texture2DContent outputTC = new Texture2DContent(); outputTC.Mipmaps = imageChain; return(outputTC); }
static void Fill <T>(PixelBitmapContent <T> content, T color) where T : struct, IEquatable <T> { var src = Enumerable.Repeat(color, content.Width * content.Height).ToArray(); var dest = ToByteArray(src); content.SetPixelData(dest); }
private bool IsNullTileSafe(PixelBitmapContent <Color> bitmap, int x, int y) { if (IsNotInBitmap(bitmap, x, y)) { return(true); } return(IsNullTile(bitmap, x, y)); }
private static void Fill(PixelBitmapContent <Color> content, Color color) { var src = Enumerable.Repeat(color.PackedValue, content.Width * content.Height).ToArray(); var dest = new byte[Marshal.SizeOf(typeof(Color)) * content.Width * content.Height]; Buffer.BlockCopy(src, 0, dest, 0, dest.Length); content.SetPixelData(dest); }
public override TextureContent Import(string filename, ContentImporterContext context) { using (FileStream file = new FileStream(filename, FileMode.Open)) { byte[] bytes = new byte[file.Length]; file.Read(bytes, 0, (int)file.Length); bool bit16 = false; // Figure out file size if (Width <= 0 || Height <= 0) { Width = (int)Math.Sqrt(file.Length); Height = (int)(file.Length / Width); if (Width * Height != file.Length) { Width = (int)Math.Sqrt(file.Length / 2); Height = (int)(file.Length / 2 / Width); bit16 = true; } if (Width * Height * 2 == file.Length) { context.Logger.LogWarning(null, new ContentIdentity(filename), "Input texture not a raw grayscale texture, or the specified width and height do not match."); } } // Create texture int i = 0; PixelBitmapContent <float> bitmap = new PixelBitmapContent <float>(Width, Height); for (int y = 0; y < Height; ++y) { for (int x = 0; x < Width; ++x) { if (bit16) { bitmap.SetPixel(x, y, 1.0f * (ushort)((bytes[i++] | bytes[i++] << 8)) / ushort.MaxValue); } else { bitmap.SetPixel(x, y, 1.0f * bytes[i++] / byte.MaxValue); } } } Texture2DContent result = new Texture2DContent(); result.Mipmaps = new MipmapChain(bitmap); return(result); } }
public override TextureContent Import(string filename, ContentImporterContext context) { Texture2DContent output; if (Path.GetExtension(filename) != ".slmc") { throw new InvalidContentException("File type not supported."); } var images = ImportSLMC(filename, context); if (images.Count < 1) { throw new InvalidContentException("Element 'channels' must have at least one 'image'."); } if (images.Count > 4) { throw new InvalidContentException("No more than 4 images are supported."); } int width = images[0].Mipmaps[0].Width; int height = images[0].Mipmaps[0].Height; // validate size foreach (var image in images) { if (image.Mipmaps[0].Width != width || image.Mipmaps[0].Height != height) { throw new InvalidContentException("Images must be of the same size."); } } var pixelCount = width * height; var byteCount = pixelCount * 4; byte[] data = new byte[byteCount]; for (int i = 0; i < images.Count; i++) { var image = images[i]; var face = image.Faces[0][0]; var pixelData = face.GetPixelData(); for (int d = 0; d < pixelCount; d++) { data[d * 4 + i] = pixelData[d * 4]; } } var bitmap = new PixelBitmapContent <Color>(width, height); bitmap.SetPixelData(data); output = new Texture2DContent(); output.Faces[0].Add(bitmap); return(output); }
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; } } // Convert to full colour 32-bit format. Floating point would be preferred for processing, but it appears the ATICompressor does not support this var colorBitmap = new PixelBitmapContent<Color>(sourceRegion.Width, sourceRegion.Height); BitmapContent.Copy(sourceBitmap, sourceRegion, colorBitmap, new Rectangle(0, 0, colorBitmap.Width, colorBitmap.Height)); sourceBitmap = colorBitmap; ATICompressor.CompressionFormat targetFormat; switch (format) { case SurfaceFormat.RgbaAtcExplicitAlpha: targetFormat = ATICompressor.CompressionFormat.AtcRgbaExplicitAlpha; break; case SurfaceFormat.RgbaAtcInterpolatedAlpha: targetFormat = ATICompressor.CompressionFormat.AtcRgbaInterpolatedAlpha; break; default: return false; } var sourceData = sourceBitmap.GetPixelData(); var compressedData = ATICompressor.Compress(sourceData, Width, Height, targetFormat); SetPixelData(compressedData); return true; }
public void BitmapCompressFullResize() { var b1 = new PixelBitmapContent <Color>(16, 16); Fill(b1, Color.Red); var b2 = new Dxt1BitmapContent(8, 8); BitmapContent.Copy(b1, b2); }
public void MipmapNonSquareNonPowerOfTwo() { var context = new TestProcessorContext(TargetPlatform.Windows, "dummy.xnb"); var processor = new TextureProcessor { ColorKeyEnabled = false, GenerateMipmaps = true, PremultiplyAlpha = false, ResizeToPowerOfTwo = false, TextureFormat = TextureProcessorOutputFormat.Color }; var width = 23; var height = 5; var face = new PixelBitmapContent <Color>(width, height); Fill(face, Color.Red); var input = new Texture2DContent(); input.Faces[0] = face; var output = processor.Process(input, context); Assert.NotNull(output); Assert.AreEqual(1, output.Faces.Count); var outChain = output.Faces[0]; Assert.AreEqual(5, outChain.Count); foreach (var outFace in outChain) { Assert.AreEqual(width, outFace.Width); Assert.AreEqual(height, outFace.Height); var bitmap = (PixelBitmapContent <Color>)outFace; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { Assert.AreEqual(Color.Red, bitmap.GetPixel(x, y)); } } if (width > 1) { width /= 2; } if (height > 1) { height /= 2; } } }
/// <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); }
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 void BitmapCopySameRegionNoResize() { 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, 4, 4)); for (var y = 0; y < b2.Height; y++) for (var x = 0; x < b2.Width; x++) Assert.AreEqual(x < 4 && y < 4 ? Color.Red : Color.Blue, b2.GetPixel(x, y)); }
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 CubeHeightmapContent(PixelBitmapContent<float> bitmap, float unitScale, int blockScale, int altitudeScale) { scale = unitScale * (float) blockScale; var xLength = bitmap.Width; var zLength = bitmap.Height; heights = new float[xLength, zLength]; for (int z = 0; z < zLength; z++) { for (int x = 0; x < xLength; x++) { //Heights[x, z] = altitudeScale * (spriteBitmap.GetPixel(x, z) - 1); int y = (int) (bitmap.GetPixel(x, z) * (float) altitudeScale); Heights[x, z] = y * Scale; } } }
public void Mipmap() { var context = new TestProcessorContext(TargetPlatform.Windows, "dummy.xnb"); var processor = new TextureProcessor { ColorKeyEnabled = false, GenerateMipmaps = true, PremultiplyAlpha = false, ResizeToPowerOfTwo = false, TextureFormat = TextureProcessorOutputFormat.Color }; var face = new PixelBitmapContent<Color>(8, 8); Fill(face, Color.Red); var input = new Texture2DContent(); input.Faces[0] = face; var output = processor.Process(input, context); Assert.NotNull(output); Assert.AreEqual(1, output.Faces.Count); //Assert.AreNotEqual(face, output.Faces[0][0]); var outChain = output.Faces[0]; Assert.AreEqual(4, outChain.Count); var width = 8; var height = 8; foreach (var outFace in outChain) { Assert.AreEqual(width, outFace.Width); Assert.AreEqual(height, outFace.Height); var bitmap = (PixelBitmapContent<Color>)outFace; for (var y = 0; y < height; y++) for (var x = 0; x < width; x++) Assert.AreEqual(Color.Red, bitmap.GetPixel(x, y)); width = width >> 1; height = height >> 1; } }
// Once arranging is complete, copies each glyph to its chosen position in the single larger output bitmap. static BitmapContent CopyGlyphsToOutput(List<ArrangedGlyph> glyphs, int width, int height) { var output = new PixelBitmapContent<Color>(width, height); foreach (var glyph in glyphs) { var sourceGlyph = glyph.Source; var sourceRegion = sourceGlyph.Subrect; var destinationRegion = new Rectangle(glyph.X + 1, glyph.Y + 1, sourceRegion.Width, sourceRegion.Height); BitmapContent.Copy(sourceGlyph.Bitmap, sourceRegion, output, destinationRegion); // TODO: This causes artifacts around borders. //BitmapUtils.PadBorderPixels(output, destinationRegion); sourceGlyph.Bitmap = output; sourceGlyph.Subrect = destinationRegion; } return output; }
/// <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 PixelBitmapContent<Color> copySpritesToOutput( List<ArrangedSprite> sprites, IList<BitmapContent> sourceSprites, ICollection<Rectangle> outputSprites, int width, int height ) { var output = new PixelBitmapContent<Color>( width, height ); foreach( var sprite in sprites ) { var source = sourceSprites[sprite.index]; var x = sprite.x; var y = sprite.y; var w = source.Width; var 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; }
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); }
internal static BitmapContent Resize(this BitmapContent bitmap, int newWidth, int newHeight) { BitmapContent src = bitmap; SurfaceFormat format; src.TryGetFormat(out format); if (format != SurfaceFormat.Vector4) { var v4 = new PixelBitmapContent<Vector4>(src.Width, src.Height); BitmapContent.Copy(src, v4); src = v4; } // Convert to FreeImage bitmap var bytes = src.GetPixelData(); var fi = FreeImage.ConvertFromRawBits(bytes, FREE_IMAGE_TYPE.FIT_RGBAF, src.Width, src.Height, SurfaceFormat.Vector4.GetSize() * src.Width, 128, 0, 0, 0, true); // Resize var newfi = FreeImage.Rescale(fi, newWidth, newHeight, FREE_IMAGE_FILTER.FILTER_BICUBIC); FreeImage.UnloadEx(ref fi); // Convert back to PixelBitmapContent<Vector4> src = new PixelBitmapContent<Vector4>(newWidth, newHeight); bytes = new byte[SurfaceFormat.Vector4.GetSize() * newWidth * newHeight]; FreeImage.ConvertToRawBits(bytes, newfi, SurfaceFormat.Vector4.GetSize() * newWidth, 128, 0, 0, 0, true); src.SetPixelData(bytes); FreeImage.UnloadEx(ref newfi); // Convert back to source type if required if (format != SurfaceFormat.Vector4) { var s = (BitmapContent)Activator.CreateInstance(bitmap.GetType(), new object[] { newWidth, newHeight }); BitmapContent.Copy(src, s); src = s; } return src; }
/// <summary> /// Converts a DigitalRune <see cref="Image"/> to an XNA <see cref="BitmapContent"/>. /// </summary> /// <param name="image">The <see cref="Image"/>.</param> /// <returns>The <see cref="BitmapContent"/>.</returns> public static BitmapContent ToContent(Image image) { BitmapContent content; switch (image.Format) { case DataFormat.R8G8B8A8_UNORM: case DataFormat.R8G8B8A8_UNORM_SRGB: content = new PixelBitmapContent<Color>(image.Width, image.Height); break; case DataFormat.B5G6R5_UNORM: content = new PixelBitmapContent<Bgr565>(image.Width, image.Height); break; #if !MONOGAME case DataFormat.B5G5R5A1_UNORM: content = new PixelBitmapContent<Bgra5551>(image.Width, image.Height); break; #endif case DataFormat.B4G4R4A4_UNORM: content = new PixelBitmapContent<Bgra4444>(image.Width, image.Height); break; case DataFormat.BC1_UNORM: case DataFormat.BC1_UNORM_SRGB: content = new Dxt1BitmapContent(image.Width, image.Height); break; case DataFormat.BC2_UNORM: case DataFormat.BC2_UNORM_SRGB: content = new Dxt3BitmapContent(image.Width, image.Height); break; case DataFormat.BC3_UNORM: case DataFormat.BC3_UNORM_SRGB: content = new Dxt5BitmapContent(image.Width, image.Height); break; case DataFormat.R8G8_SNORM: content = new PixelBitmapContent<NormalizedByte2>(image.Width, image.Height); break; case DataFormat.R8G8B8A8_SNORM: content = new PixelBitmapContent<NormalizedByte4>(image.Width, image.Height); break; #if !MONOGAME case DataFormat.R10G10B10A2_UNORM: content = new PixelBitmapContent<Rgba1010102>(image.Width, image.Height); break; case DataFormat.R16G16_UNORM: content = new PixelBitmapContent<Rg32>(image.Width, image.Height); break; case DataFormat.R16G16B16A16_UNORM: content = new PixelBitmapContent<Rgba64>(image.Width, image.Height); break; case DataFormat.A8_UNORM: case DataFormat.R8_UNORM: content = new PixelBitmapContent<Alpha8>(image.Width, image.Height); break; #endif case DataFormat.R32_FLOAT: content = new PixelBitmapContent<float>(image.Width, image.Height); break; case DataFormat.R32G32_FLOAT: content = new PixelBitmapContent<Vector2>(image.Width, image.Height); break; case DataFormat.R32G32B32A32_FLOAT: content = new PixelBitmapContent<Vector4>(image.Width, image.Height); break; case DataFormat.R16_FLOAT: content = new PixelBitmapContent<HalfSingle>(image.Width, image.Height); break; case DataFormat.R16G16_FLOAT: content = new PixelBitmapContent<HalfVector2>(image.Width, image.Height); break; case DataFormat.R16G16B16A16_FLOAT: content = new PixelBitmapContent<HalfVector4>(image.Width, image.Height); break; #if MONOGAME case DataFormat.PVRTCI_2bpp_RGB: content = new PvrtcRgb2BitmapContent(image.Width, image.Height); break; case DataFormat.PVRTCI_4bpp_RGB: content = new PvrtcRgb4BitmapContent(image.Width, image.Height); break; case DataFormat.PVRTCI_2bpp_RGBA: content = new PvrtcRgba2BitmapContent(image.Width, image.Height); break; case DataFormat.PVRTCI_4bpp_RGBA: content = new PvrtcRgba4BitmapContent(image.Width, image.Height); break; case DataFormat.ETC1: content = new Etc1BitmapContent(image.Width, image.Height); break; //case DataFormat.ATC_RGB: Not supported in MonoGame. case DataFormat.ATC_RGBA_EXPLICIT_ALPHA: content = new AtcExplicitBitmapContent(image.Width, image.Height); break; case DataFormat.ATC_RGBA_INTERPOLATED_ALPHA: content = new AtcInterpolatedBitmapContent(image.Width, image.Height); break; #endif default: string message = string.Format("The texture format {0} is not supported in MonoGame.", image.Format); throw new NotSupportedException(message); // Not supported: // SurfaceFormat.HdrBlendable // Only needed as render target format. // SurfaceFormat.Bgr32 // Only used as WPF render target. // SurfaceFormat.Bgra32 // Only used as WPF render target. // SurfaceFormat.Dxt1a } Debug.Assert(content != null); #if !MONOGAME // content.GetPixelData() is null in MonoGame. Debug.Assert(image.Data.Length == content.GetPixelData().Length); #endif content.SetPixelData(image.Data); return content; }
/// <summary> /// 圧縮ブロックの処理 /// </summary> /// <param name="source">元画像</param> /// <param name="blockX">Xブロック位置</param> /// <param name="blockY">Yブロック位置</param> /// <param name="color0">単色カラー</param> /// <param name="outputData">出力先</param> /// <param name="outputIndex">出力オフセット</param> private static void CompressDxt3Block(PixelBitmapContent<Color> source, int blockX, int blockY, ushort color0, byte[] outputData, int outputIndex) { long alphaBits = 0; int rgbBits = 0; int pixelCount = 0; // 4x4ブロック内の処理 for (int y = 0; y < 4; ++y) { for (int x = 0; x < 4; ++x) { // 元のアルファ値の取得 int value = source.GetPixel(blockX + x, blockY + y).A; int alpha = 0; int rgb = 0; // アルファ値によって、出力値を決定。 // ここでは単純にアルファ値領域を4分割するのではなく、6分割にして // 1/6、1/2、5/6の非線形の閾値を使っている if (value < 256 / 6) { alpha = 0; rgb = 1; // c1色 = 0 } else if (value < 256 * 3 / 6) { alpha = 5; rgb = 3; // c3色 = 1/3(c0) + 2/3(c1) = 85 } else if (value < 256 * 5 / 6) { alpha = 10; rgb = 2; // c2色 = 1/2(c0) + 1/2(c1) = 127 } else { alpha = 15; rgb = 0; // c0色 = 255 } // 計算結果ビットを格納 alphaBits |= (long)alpha << (pixelCount * 4); rgbBits |= rgb << (pixelCount * 2); pixelCount++; } } // DXT3ブロック情報の出力 // アルファ 8バイト for (int i = 0; i < 8; ++i) { outputData[outputIndex + i] = (byte)(alphaBits >> (i * 8)); } // カラー値(c0, c1) 4バイト // c0 outputData[outputIndex + 8] = (byte)(color0 & 0xff); outputData[outputIndex + 9] = (byte)((color0 >> 8) & 0xff); // c1 outputData[outputIndex + 10] = 0x00; outputData[outputIndex + 11] = 0x00; // RGB情報 4バイト for (int i = 0; i < 4; ++i) { outputData[outputIndex + 12 + i] = (byte)(rgbBits >> (i * 8)); } }
// Rasterizes a single character glyph. private Glyph ImportGlyph(char character, Face face) { uint glyphIndex = face.GetCharIndex(character); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); // Render the character. BitmapContent glyphBitmap = null; if (face.Glyph.Bitmap.Width > 0 && face.Glyph.Bitmap.Rows > 0) { glyphBitmap = new PixelBitmapContent<byte>(face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows); byte[] gpixelAlphas = new byte[face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows]; //if the character bitmap has 1bpp we have to expand the buffer data to get the 8bpp pixel data //each byte in bitmap.bufferdata contains the value of to 8 pixels in the row //if bitmap is of width 10, each row has 2 bytes with 10 valid bits, and the last 6 bits of 2nd byte must be discarded if(face.Glyph.Bitmap.PixelMode == PixelMode.Mono) { //variables needed for the expansion, amount of written data, length of the data to write int written = 0, length = face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows; for(int i = 0; written < length; i++) { //width in pixels of each row int width = face.Glyph.Bitmap.Width; while(width > 0) { //valid data in the current byte int stride = MathHelper.Min(8, width); //copy the valid bytes to pixeldata //System.Array.Copy(ExpandByte(face.Glyph.Bitmap.BufferData[i]), 0, gpixelAlphas, written, stride); ExpandByteAndCopy(face.Glyph.Bitmap.BufferData[i], stride, gpixelAlphas, written); written += stride; width -= stride; if(width > 0) i++; } } } else Marshal.Copy(face.Glyph.Bitmap.Buffer, gpixelAlphas, 0, gpixelAlphas.Length); glyphBitmap.SetPixelData(gpixelAlphas); } if (glyphBitmap == null) { var gHA = face.Glyph.Metrics.HorizontalAdvance >> 6; var gVA = face.Size.Metrics.Height >> 6; gHA = gHA > 0 ? gHA : gVA; gVA = gVA > 0 ? gVA : gHA; glyphBitmap = new PixelBitmapContent<byte>(gHA, gVA); } // not sure about this at all var abc = new ABCFloat (); abc.A = face.Glyph.Metrics.HorizontalBearingX >> 6; abc.B = face.Glyph.Metrics.Width >> 6; abc.C = (face.Glyph.Metrics.HorizontalAdvance >> 6) - (abc.A + abc.B); // Construct the output Glyph object. return new Glyph(character, glyphBitmap) { XOffset = -(face.Glyph.Advance.X >> 6), XAdvance = face.Glyph.Metrics.HorizontalAdvance >> 6, YOffset = -(face.Glyph.Metrics.HorizontalBearingY >> 6), CharacterWidths = abc }; }
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 static BitmapContent ToXnaBitmap(this Bitmap systemBitmap, bool flipColors) { // Any bitmap using this function should use 32bpp ARGB pixel format, since we have to // swizzle the channels later System.Diagnostics.Debug.Assert(systemBitmap.PixelFormat == PixelFormat.Format32bppArgb); var bitmapData = systemBitmap.LockBits(new System.Drawing.Rectangle(0, 0, systemBitmap.Width, systemBitmap.Height), ImageLockMode.ReadOnly, systemBitmap.PixelFormat); var length = bitmapData.Stride * bitmapData.Height; var pixelData = new byte[length]; // Copy bitmap to byte[] Marshal.Copy(bitmapData.Scan0, pixelData, 0, length); systemBitmap.UnlockBits(bitmapData); // NOTE: According to http://msdn.microsoft.com/en-us/library/dd183449%28VS.85%29.aspx // and http://stackoverflow.com/questions/8104461/pixelformat-format32bppargb-seems-to-have-wrong-byte-order // Image data from any GDI based function are stored in memory as BGRA/BGR, even if the format says RGBA. // Because of this we flip the R and B channels. if(flipColors) BGRAtoRGBA(pixelData); var xnaBitmap = new PixelBitmapContent<Color>(systemBitmap.Width, systemBitmap.Height); xnaBitmap.SetPixelData(pixelData); return xnaBitmap; }
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; }
/// <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; }
public void ColorConversion() { var context = new TestProcessorContext(TargetPlatform.Windows, "dummy.xnb"); var processor = new FontTextureProcessor { FirstCharacter = '0', PremultiplyAlpha = false }; var face = new PixelBitmapContent<Color>(32, 9); var O = Color.Transparent.PackedValue; var M = Color.Fuchsia.PackedValue; var R = Color.Red.PackedValue; var G = Color.Green.PackedValue; var B = Color.Blue.PackedValue; var W = Color.White.PackedValue; var pixelData = new[] { M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, O, O, O, O, O, O, M, M, O, O, O, O, O, O, M, M, O, O, O, O, O, O, M, M, O, O, O, O, O, O, M, M, O, O, W, W, O, O, M, M, O, O, O, R, O, O, M, M, O, G, G, G, O, O, M, M, O, B, B, B, B, O, M, M, O, W, O, O, W, O, M, M, O, O, R, R, O, O, M, M, O, O, O, O, G, O, M, M, O, O, O, B, O, O, M, M, O, W, O, O, W, O, M, M, O, O, O, R, O, O, M, M, O, O, G, G, O, O, M, M, O, O, B, B, O, O, M, M, O, W, O, O, W, O, M, M, O, O, O, R, O, O, M, M, O, G, O, O, O, O, M, M, O, O, O, O, B, O, M, M, O, O, W, W, O, O, M, M, O, R, R, R, R, O, M, M, O, G, G, G, G, O, M, M, O, B, B, B, O, O, M, M, O, O, O, O, O, O, M, M, O, O, O, O, O, O, M, M, O, O, O, O, O, O, M, M, O, O, O, O, O, O, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, M, }; var pixelBytes = new byte[face.Width * 4 * face.Height]; Buffer.BlockCopy(pixelData, 0, pixelBytes, 0, pixelData.Length * 4); face.SetPixelData(pixelBytes); var input = new Texture2DContent(); input.Faces[0] = face; var output = processor.Process(input, context); Assert.NotNull(output); Assert.AreEqual(output.CharacterMap[0], '0'); Assert.AreEqual(output.CharacterMap[1], '1'); Assert.AreEqual(output.CharacterMap[2], '2'); Assert.AreEqual(output.CharacterMap[3], '3'); Assert.AreEqual(1, output.Texture.Faces.Count); Assert.AreEqual(1, output.Texture.Faces[0].Count); Assert.IsAssignableFrom<PixelBitmapContent<Color>>(output.Texture.Faces[0][0]); var outFace = (PixelBitmapContent<Color>)output.Texture.Faces[0][0]; for (var i = 0; i < 4; ++i) { // (2, 2, 4, 5) is the top,left and width,height of the first glyph. All test glyphs are 4x5 var inRect = new Rectangle(i * 8 + 2, 2, 4, 5); var outRect = output.Glyphs[i]; Assert.AreEqual(inRect.Width, outRect.Width); Assert.AreEqual(inRect.Height, outRect.Height); for (var y = 0; y < inRect.Height; ++y) for (var x = 0; x < inRect.Width; ++x) Assert.AreEqual(pixelData[(x + inRect.Left) + (y + inRect.Top) * face.Width], outFace.GetPixel(x + outRect.Left, y + outRect.Top).PackedValue); } Assert.AreEqual(new Rectangle(1, 1, 6, 7), output.Cropping[0]); Assert.AreEqual(new Rectangle(1, 1, 6, 7), output.Cropping[1]); Assert.AreEqual(new Rectangle(1, 1, 6, 7), output.Cropping[2]); Assert.AreEqual(new Rectangle(1, 1, 6, 7), output.Cropping[3]); }
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; }
/// <summary> /// Copies one bitmap into another. /// The destination bitmap can be in any format and size. If the destination is larger or smaller, the source bitmap is scaled accordingly. /// </summary> /// <param name="sourceBitmap">BitmapContent being copied.</param> /// <param name="sourceRegion">Region of sourceBitmap.</param> /// <param name="destinationBitmap">BitmapContent being overwritten.</param> /// <param name="destinationRegion">Region of bitmap to be overwritten.</param> public static void Copy(BitmapContent sourceBitmap, Rectangle sourceRegion, BitmapContent destinationBitmap, Rectangle destinationRegion) { ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); SurfaceFormat sourceFormat; if (!sourceBitmap.TryGetFormat(out sourceFormat)) throw new InvalidOperationException("Could not retrieve surface format of source bitmap"); SurfaceFormat destinationFormat; if (!destinationBitmap.TryGetFormat(out destinationFormat)) throw new InvalidOperationException("Could not retrieve surface format of destination bitmap"); // If the formats are the same and the regions are the full bounds of the bitmaps and they are the same size, do a simpler copy if (sourceFormat == destinationFormat && sourceRegion == destinationRegion && sourceRegion == new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height) && destinationRegion == new Rectangle(0, 0, destinationBitmap.Width, destinationBitmap.Height)) { destinationBitmap.SetPixelData(sourceBitmap.GetPixelData()); return; } // The basic process is // 1. Copy from source bitmap region to a new PixelBitmapContent<Vector4> using sourceBitmap.TryCopyTo() // 2. If source and destination regions are a different size, resize Vector4 version // 3. Copy from Vector4 to destination region using destinationBitmap.TryCopyFrom() // Copy from the source to the intermediate Vector4 format var intermediate = new PixelBitmapContent<Vector4>(sourceRegion.Width, sourceRegion.Height); var intermediateRegion = new Rectangle(0, 0, intermediate.Width, intermediate.Height); if (sourceBitmap.TryCopyTo(intermediate, sourceRegion, intermediateRegion)) { // Resize the intermediate if required if (intermediate.Width != destinationRegion.Width || intermediate.Height != destinationRegion.Height) intermediate = intermediate.Resize(destinationRegion.Width, destinationRegion.Height) as PixelBitmapContent<Vector4>; // Copy from the intermediate to the destination if (destinationBitmap.TryCopyFrom(intermediate, new Rectangle(0, 0, intermediate.Width, intermediate.Height), destinationRegion)) return; } // If we got here, one of the above steps didn't work throw new InvalidOperationException("Could not copy between " + sourceFormat + " and " + destinationFormat); }
internal static void Resize(this TextureContent content, int newWidth, int newHeight) { var resizedBmp = new Bitmap(newWidth, newHeight); using (var graphics = System.Drawing.Graphics.FromImage(resizedBmp)) { graphics.DrawImage(content._bitmap, 0, 0, newWidth, newHeight); content._bitmap.Dispose(); content._bitmap = resizedBmp; } var imageData = content._bitmap.GetData(); var bitmapContent = new PixelBitmapContent<Color>(content._bitmap.Width, content._bitmap.Height); bitmapContent.SetPixelData(imageData); content.Faces.Clear(); content.Faces.Add(new MipmapChain(bitmapContent)); }