Пример #1
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);
        }
        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);
        }
Пример #3
0
 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);
 }
        /// <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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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.
            if (input._bitmap == null)
            {
                throw new ArgumentNullException("Texture Bitmap cannot be null");
            }

            int linespacing = 0;
            var glyphs      = ExtractGlyphs(input._bitmap, out linespacing);

            // Optimize.
            foreach (Glyph glyph in glyphs)
            {
                GlyphCropper.Crop(glyph);
            }

            var outputBitmap = GlyphPacker.ArrangeGlyphs(glyphs.ToArray(), true, true);

            //outputBitmap.Save ("fontglyphs.png");


            foreach (Glyph glyph in glyphs)
            {
                glyph.XAdvance += linespacing;
                if (!output.CharacterMap.Contains(glyph.Character))
                {
                    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(0, 0, glyph.Subrect.Width, glyph.Subrect.Height));
                ABCFloat abc = glyph.CharacterWidths;
                output.Kerning.Add(new Vector3(abc.A, abc.B, abc.C));
            }

            output.Texture._bitmap = outputBitmap;

            var bitmapContent = new PixelBitmapContent <Color> (outputBitmap.Width, outputBitmap.Height);

            bitmapContent.SetPixelData(outputBitmap.GetData());
            output.Texture.Faces.Add(new MipmapChain(bitmapContent));

            GraphicsUtil.CompressTexture(output.Texture, context, false, false);

            return(output);
        }
Пример #10
0
        // Loads BMP using StbSharp. This allows us to load BMP files containing BITMAPV4HEADER and BITMAPV5HEADER
        // structures, which FreeImage does not support.
        TextureContent LoadImage(string filename)
        {
            var output = new Texture2DContent {
                Identity = new ContentIdentity(filename)
            };

            int width, height, comp;

            byte[] data = null;
            using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
                data = ImageReader.Read(stream, out width, out height, out comp, Imaging.STBI_rgb_alpha);

            var face = new PixelBitmapContent <Color>(width, height);

            face.SetPixelData(data);
            output.Faces[0].Add(face);

            return(output);
        }
Пример #11
0
        // Loads BMP using StbSharp. This allows us to load BMP files containing BITMAPV4HEADER and BITMAPV5HEADER
        // structures, which FreeImage does not support.
        TextureContent LoadImage(string filename)
        {
            var output = new Texture2DContent {
                Identity = new ContentIdentity(filename)
            };

            ImageResult result;

            using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                var imageLoader = new ImageStreamLoader();
                result = imageLoader.Load(stream, ColorComponents.RedGreenBlueAlpha);
            }

            var face = new PixelBitmapContent <Color>(result.Width, result.Height);

            face.SetPixelData(result.Data);
            output.Faces[0].Add(face);

            return(output);
        }
Пример #12
0
        /// <summary>
        /// Called by the XNA Framework when importing a texture audio 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();
            var bmp    = new Bitmap(filename);

            var bitmapContent = new PixelBitmapContent <Color>(bmp.Width, bmp.Height);

            var bitmapData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
                                          System.Drawing.Imaging.ImageLockMode.ReadOnly,
                                          System.Drawing.Imaging.PixelFormat.DontCare);

            var length    = bitmapData.Stride * bitmapData.Height;
            var imageData = new byte[length];

            // Copy bitmap to byte[]
            Marshal.Copy(bitmapData.Scan0, imageData, 0, length);
            bmp.UnlockBits(bitmapData);

            bitmapContent.SetPixelData(imageData);

            output.Faces[0].Add(bitmapContent);
            return(output);
        }
Пример #13
0
        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;
        }
        public override SpriteFontContent Process(FontDescription input,
                                                  ContentProcessorContext context)
        {
            var output = new SpriteFontContent(input);

            var estimatedSurfaceArea = 0;
            var largestHeight        = 0;
            var widthsAndHeights     = new List <Point>();
            var fontName             = input.FontName;

            var directory = Path.GetDirectoryName(input.Identity.SourceFilename);

            if (File.Exists(Path.Combine(directory, fontName + ".ttf")))
            {
                fontName += ".ttf";
            }
            if (File.Exists(Path.Combine(directory, fontName + ".ttc")))
            {
                fontName += ".ttc";
            }
            if (File.Exists(Path.Combine(directory, fontName + ".otf")))
            {
                fontName += ".otf";
            }

            fontName = Path.Combine(directory, fontName);
            context.Logger.LogMessage("Building Font {0}", fontName);
            try {
                Library lib  = new Library();
                Face    face = lib.NewFace(fontName, 0);
                face.SetCharSize(0, (int)input.Size * 64, 0, 96);

                if (face.FamilyName == "Microsoft Sans Serif" && input.FontName != "Microsoft Sans Serif")
                {
                    throw new PipelineException(string.Format("Font {0} is not installed on this computer.", input.FontName));
                }

                foreach (var ch in input.Characters)
                {
                    uint glyphIndex = face.GetCharIndex(ch);
                    face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                    var width = (int)face.Glyph.Advance.X >> 6;

                    var height = (int)face.Glyph.Metrics.Height >> 6;

                    estimatedSurfaceArea += width;
                    largestHeight         = Math.Max(largestHeight, height);

                    widthsAndHeights.Add(new Point(width, height));
                }

                estimatedSurfaceArea *= largestHeight;

                output.VerticalLineSpacing = largestHeight;

                // calculate the best height and width for our output texture.
                // TODO: GetMonoGamePlatform()
                var texBounds = calculateOutputTextureBounds(estimatedSurfaceArea, true);
                // Create our texture
                var outputBitmap = new Bitmap(texBounds.X, texBounds.Y);
                using (var g = System.Drawing.Graphics.FromImage(outputBitmap))
                {
                    g.FillRectangle(Brushes.Transparent, new System.Drawing.Rectangle(0, 0, outputBitmap.Width, outputBitmap.Height));
                }
                int x = 0;
                int y = 0;
                // Draw each glyph into the image.
                for (int i = 0; i < input.Characters.Count; i++)
                {
                    char c          = input.Characters[i];
                    uint glyphIndex = face.GetCharIndex(c);
                    face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                    face.Glyph.RenderGlyph(RenderMode.Normal);

                    var A = face.Glyph.Metrics.HorizontalBearingX >> 6;
                    var B = face.Glyph.Metrics.Width >> 6;
                    var C = (face.Glyph.Metrics.HorizontalAdvance >> 6) - (A + B);

                    int charWidth = (int)(Math.Abs(A) + B + C);

                    if (!input.UseKerning)
                    {
                        charWidth = (int)B;
                    }

                    if (x + charWidth >= outputBitmap.Width)
                    {
                        x  = 0;
                        y += largestHeight;
                    }

                    var rect = new Microsoft.Xna.Framework.Rectangle(x, y, charWidth, widthsAndHeights[i].Y);
                    output.Glyphs.Add(rect);

                    // Characters with a negative a kerning value (like j) need to be adjusted,
                    // so (in the case of j) the bottom curve doesn't render outside our source
                    // rect.
                    var renderPoint = new PointF(x, y);
                    if (A < 0)
                    {
                        renderPoint.X += Math.Abs(A);
                    }

                    if (face.Glyph.Bitmap.Width > 0 && face.Glyph.Bitmap.Rows > 0)
                    {
                        BitmapData data        = outputBitmap.LockBits(new System.Drawing.Rectangle((int)renderPoint.X, (int)renderPoint.Y, face.Glyph.Bitmap.Width, face.Glyph.Bitmap.Rows), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                        byte[]     pixelAlphas = new byte[face.Glyph.Bitmap.Width * face.Glyph.Bitmap.Rows];
                        Marshal.Copy(face.Glyph.Bitmap.Buffer, pixelAlphas, 0, pixelAlphas.Length);

                        for (int j = 0; j < pixelAlphas.Length; j++)
                        {
                            int pixelOffset = (j / data.Width) * data.Stride + (j % data.Width * 4);
                            Marshal.WriteByte(data.Scan0, pixelOffset + 3, pixelAlphas[j]);
                        }

                        outputBitmap.UnlockBits(data);
                    }
                    output.Cropping.Add(new Microsoft.Xna.Framework.Rectangle(0, (face.Glyph.Metrics.VerticalAdvance >> 6) - face.Glyph.BitmapTop, charWidth, widthsAndHeights[i].Y));

                    if (!input.UseKerning)
                    {
                        A = 0;
                        C = 0;
                    }
                    output.Kerning.Add(new Vector3(A, B, C));

                    // Add a 2 pixel spacing between characters
                    x += charWidth + 2;
                }

                // Drawing against a transparent black background blends
                // the 'alpha' pixels against black, leaving a black outline.
                // Interpolate between black and white
                // based on it's intensity to covert this 'outline' to
                // it's grayscale equivalent.
                var transBlack = Color.Transparent;
                for (var i = 0; i < outputBitmap.Width; i++)
                {
                    for (var j = 0; j < outputBitmap.Height; j++)
                    {
                        var px = outputBitmap.GetPixel(i, j);

                        if (px.ColorsEqual(transBlack))
                        {
                            continue;
                        }

                        var val = px.A / (255.0f);
                        var col = Color.Lerp(Color.Transparent, Color.White, val);
                        px = System.Drawing.Color.FromArgb(px.A, col.R, col.G, col.B);
                        outputBitmap.SetPixel(i, j, px);
                    }
                }
                outputBitmap.Save("test.png");
                output.Texture._bitmap = outputBitmap;

                var bitmapContent = new PixelBitmapContent <Color>(texBounds.X, texBounds.Y);
                bitmapContent.SetPixelData(outputBitmap.GetData());
                output.Texture.Faces.Add(new MipmapChain(bitmapContent));

                GraphicsUtil.CompressTexture(output.Texture, context, false, false);
            }
            catch (Exception ex) {
                context.Logger.LogImportantMessage("{0}", ex.ToString());
            }

            return(output);
        }
Пример #15
0
        public override SpriteFontContent Process(FontDescription input,
                                                  ContentProcessorContext context)
        {
            var output = new SpriteFontContent(input);

            var fontName = input.FontName;

#if WINDOWS
            var windowsfolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
            var fontDirectory = Path.Combine(windowsfolder, "Fonts");
            fontName = FindFontFileFromFontName(fontName, fontDirectory);
            if (string.IsNullOrWhiteSpace(fontName))
            {
                fontName = input.FontName;
#endif

            var directory   = Path.GetDirectoryName(input.Identity.SourceFilename);
            var directories = new string[] { directory,
                                             "/Library/Fonts",
#if WINDOWS
                                             fontDirectory,
#endif
            }
            ;

            foreach (var dir in directories)
            {
                if (File.Exists(Path.Combine(dir, fontName + ".ttf")))
                {
                    fontName += ".ttf";
                    directory = dir;
                    break;
                }
                if (File.Exists(Path.Combine(dir, fontName + ".ttc")))
                {
                    fontName += ".ttc";
                    directory = dir;
                    break;
                }
                if (File.Exists(Path.Combine(dir, fontName + ".otf")))
                {
                    fontName += ".otf";
                    directory = dir;
                    break;
                }
            }

            fontName = Path.Combine(directory, fontName);
#if WINDOWS
        }
#endif

            context.Logger.LogMessage("Building Font {0}", fontName);
            try {
                if (!File.Exists(fontName))
                {
                    throw new Exception(string.Format("Could not load {0}", fontName));
                }
                var lineSpacing = 0f;
                var glyphs      = ImportFont(input, out lineSpacing, context, fontName);

                // Optimize.
                foreach (Glyph glyph in glyphs)
                {
                    GlyphCropper.Crop(glyph);
                }

                Bitmap outputBitmap = GlyphPacker.ArrangeGlyphs(glyphs, true, true);

                //outputBitmap.Save ("/Users/Jimmy/Desktop/Cocos2D-XNAImages/fontglyphs.png");

                // Adjust line and character spacing.
                lineSpacing += input.Spacing;

                foreach (Glyph glyph in glyphs)
                {
                    glyph.XAdvance += input.Spacing;
                    if (!output.CharacterMap.Contains(glyph.Character))
                    {
                        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(0, (int)(glyph.YOffset + glyphs.Select(x => x.YOffset).Max()), glyph.Subrect.Width, glyph.Subrect.Height));
                    ABCFloat abc = glyph.CharacterWidths;
                    output.Kerning.Add(new Vector3(abc.A, abc.B, abc.C));
                }

//				outputBitmap.Save("/Users/Jimmy/Desktop/Cocos2D-XNAImages/test.png");
                output.Texture._bitmap = outputBitmap;

                var bitmapContent = new PixelBitmapContent <Color>(outputBitmap.Width, outputBitmap.Height);
                bitmapContent.SetPixelData(outputBitmap.GetData());
                output.Texture.Faces.Add(new MipmapChain(bitmapContent));

                GraphicsUtil.CompressTexture(output.Texture, context, false, false);
            }
            catch (Exception ex) {
                context.Logger.LogImportantMessage("{0}", ex.ToString());
            }

            return(output);
        }
Пример #16
0
        public override NodeContent Import(string filename, ContentImporterContext context)
        {
            context.Logger.LogMessage("Importing H3D file: {0}", filename);

            _identity = new ContentIdentity(filename, GetType().Name);
            _rootNode = new NodeContent()
            {
                Identity = _identity, Name = "RootNode"
            };

            var scene = FormatIdentifier.IdentifyAndOpen(filename);
            var model = scene.Models[0];

            if (!scene.Textures.Any())
            {
                var path = Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}@Textures{Path.GetExtension(filename)}");
                if (File.Exists(path))
                {
                    context.Logger.LogMessage($"Found texture file {path}. Loading data...");
                    scene.Merge(FormatIdentifier.IdentifyAndOpen(path, model.Skeleton));
                }
                else
                {
                    context.Logger.LogMessage($"Couldn't find texture file {path}!");
                }
            }

            // Textures
            var textures = new Dictionary <string, Texture2DContent>();

            foreach (var texture in scene.Textures)
            {
                var bitmapContent = new PixelBitmapContent <Color>(texture.Width, texture.Height)
                {
                    Identity = _identity,
                    Name     = texture.Name
                };
                bitmapContent.SetPixelData(texture.ToRGBA());

                var textureContent = new Texture2DContent()
                {
                    Identity = _identity,
                    Name     = texture.Name
                };
                textureContent.Faces[0].Add(bitmapContent);
                textures.Add(textureContent.Name, textureContent);
            }

            // Materials
            var materials = new Dictionary <string, H3DMaterialContent>();

            foreach (var material in model.Materials)
            {
#if DEBUG
                var hlslCode = new HLSLShaderGenerator(material.MaterialParams)
                {
                    BoneCount = model.Skeleton.Count
                }.GetShader();
                var glslCode = new GLSLFragmentShaderGenerator(material.MaterialParams).GetFragShader();
#endif
                var materialContent = new H3DMaterialContent()
                {
                    Identity = _identity,
                    Name     = material.Name,

                    Effect = new EffectContent
                    {
                        Identity   = _identity,
                        Name       = "H3DEffect",
                        EffectCode = new HLSLShaderGenerator(material.MaterialParams)
                        {
                            BoneCount = model.Skeleton.Count
                        }.GetShader()
                    },
                    Material = material.Name,

                    FaceCulling = (H3DFaceCulling?)material.MaterialParams.FaceCulling,

                    EmissionColor      = material.MaterialParams.EmissionColor.ToXNA(),
                    AmbientColor       = material.MaterialParams.AmbientColor.ToXNA(),
                    DiffuseColor       = material.MaterialParams.DiffuseColor.ToXNA(),
                    Specular0Color     = material.MaterialParams.Specular0Color.ToXNA(),
                    Specular1Color     = material.MaterialParams.Specular1Color.ToXNA(),
                    Constant0Color     = material.MaterialParams.Constant0Color.ToXNA(),
                    Constant1Color     = material.MaterialParams.Constant1Color.ToXNA(),
                    Constant2Color     = material.MaterialParams.Constant2Color.ToXNA(),
                    Constant3Color     = material.MaterialParams.Constant3Color.ToXNA(),
                    Constant4Color     = material.MaterialParams.Constant4Color.ToXNA(),
                    Constant5Color     = material.MaterialParams.Constant5Color.ToXNA(),
                    BlendColor         = material.MaterialParams.BlendColor.ToXNA(),
                    DepthBufferRead    = material.MaterialParams.DepthBufferRead,
                    DepthBufferWrite   = material.MaterialParams.DepthBufferWrite,
                    StencilBufferRead  = material.MaterialParams.StencilBufferRead,
                    StencilBufferWrite = material.MaterialParams.StencilBufferWrite,
                };

                var texCount = 0;
                if (material.EnabledTextures[0])
                {
                    texCount++;
                }
                if (material.EnabledTextures[1])
                {
                    texCount++;
                }
                if (material.EnabledTextures[2])
                {
                    texCount++;
                }
                materialContent.TextureList = new Texture2DContent[texCount];
                if (material.EnabledTextures[0])
                {
                    materialContent.TextureList[0] = textures[material.Texture0Name];
                }
                if (material.EnabledTextures[1])
                {
                    materialContent.TextureList[1] = textures[material.Texture1Name];
                }
                if (material.EnabledTextures[2])
                {
                    materialContent.TextureList[2] = textures[material.Texture2Name];
                }

                materialContent.TextureSamplerSettings = material.TextureMappers.Select(tm => new TextureSamplerSettings()
                {
                    WrapU     = tm.WrapU.ToXNAWrap(),
                    WrapV     = tm.WrapV.ToXNAWrap(),
                    MagFilter = (TextureSamplerSettings.TextureMagFilter)tm.MagFilter,
                    MinFilter = (TextureSamplerSettings.TextureMinFilter)tm.MinFilter
                }).ToArray();

                materials.Add(material.Name, materialContent);
            }

            // Geometry
            var meshes = new List <MeshContent>();
            for (var i = 0; i < model.Meshes.Count; i++)
            {
                var modelMesh = model.Meshes[i];

                if (modelMesh.Type == H3DMeshType.Silhouette)
                {
                    continue;
                }

                var mesh = new MeshContent()
                {
                    Identity = _identity,
                    Name     = $"{model.Materials[modelMesh.MaterialIndex].Name}_node{i}",
                };
                var geometry = new GeometryContent
                {
                    Identity = _identity,
                    Material = materials[model.Materials[modelMesh.MaterialIndex].Name]
                };
                var vertices   = GetWorldSpaceVertices(model.Skeleton, modelMesh);
                var baseVertex = mesh.Positions.Count;
                foreach (var vertex in vertices)
                {
                    mesh.Positions.Add(vertex.Position.ToVector3());
                }
                geometry.Vertices.AddRange(Enumerable.Range(baseVertex, vertices.Length));

                foreach (var attribute in modelMesh.Attributes)
                {
                    if (attribute.Name >= PICAAttributeName.BoneIndex)
                    {
                        continue;
                    }

                    switch (attribute.Name)
                    {
                    case PICAAttributeName.Position: break;     // Already added

                    case PICAAttributeName.Normal:
                        geometry.Vertices.Channels.Add(VertexChannelNames.Normal(0), vertices.Select(vertex => vertex.Normal.ToVector3()));
                        break;

                    case PICAAttributeName.Tangent:
                        geometry.Vertices.Channels.Add(VertexChannelNames.Tangent(0), vertices.Select(vertex => vertex.Tangent.ToVector3()));
                        break;

                    case PICAAttributeName.Color:
                        geometry.Vertices.Channels.Add(VertexChannelNames.Color(0), vertices.Select(vertex => vertex.Color.ToColor()));
                        break;

                    case PICAAttributeName.TexCoord0:
                        geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(0), vertices.Select(vertex => vertex.TexCoord0.ToVector2().ToUV()));
                        break;

                    case PICAAttributeName.TexCoord1:
                        geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(1), vertices.Select(vertex => vertex.TexCoord1.ToVector2().ToUV()));
                        break;

                    case PICAAttributeName.TexCoord2:
                        geometry.Vertices.Channels.Add(VertexChannelNames.TextureCoordinate(2), vertices.Select(vertex => vertex.TexCoord2.ToVector2().ToUV()));
                        break;
                    }
                }

                var vertexOffset = 0;
                var xnaWeights   = new List <BoneWeightCollection>();
                foreach (var modelSubMesh in modelMesh.SubMeshes)
                {
                    geometry.Indices.AddRange(modelSubMesh.Indices.Select(index => (int)index));

                    var vertexCount     = modelSubMesh.MaxIndex + 1 - vertexOffset;
                    var subMeshVertices = vertices.Skip(vertexOffset).Take(vertexCount).ToList();

                    if (modelSubMesh.Skinning == H3DSubMeshSkinning.Smooth)
                    {
                        foreach (var vertex in subMeshVertices)
                        {
                            var list = new BoneWeightCollection();
                            for (var index = 0; index < 4; index++)
                            {
                                var bIndex = vertex.Indices[index];
                                var weight = vertex.Weights[index];

                                if (weight == 0)
                                {
                                    break;
                                }

                                if (bIndex < modelSubMesh.BoneIndicesCount && bIndex > -1)
                                {
                                    bIndex = modelSubMesh.BoneIndices[bIndex];
                                }
                                else
                                {
                                    bIndex = 0;
                                }

                                list.Add(new BoneWeight(model.Skeleton[bIndex].Name, weight));
                            }
                            xnaWeights.Add(list);
                        }
                    }
                    else
                    {
                        foreach (var vertex in vertices)
                        {
                            var bIndex = vertex.Indices[0];

                            if (bIndex < modelSubMesh.BoneIndices.Length && bIndex > -1)
                            {
                                bIndex = modelSubMesh.BoneIndices[bIndex];
                            }
                            else
                            {
                                bIndex = 0;
                            }

                            xnaWeights.Add(new BoneWeightCollection()
                            {
                                new BoneWeight(model.Skeleton[bIndex].Name, 0)
                            });
                        }
                    }
                    vertexOffset += vertexCount;
                }
                geometry.Vertices.Channels.Add(VertexChannelNames.Weights(0), xnaWeights);
                mesh.Geometry.Add(geometry);
                meshes.Add(mesh);
            }

            foreach (var mesh in meshes)
            {
                _rootNode.Children.Add(mesh);
            }

            var rootBone = ImportBones(model);
            _rootNode.Children.Add(rootBone);

            if (!scene.SkeletalAnimations.Any())
            {
                var path = Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}@Animations{Path.GetExtension(filename)}");
                if (File.Exists(path))
                {
                    context.Logger.LogMessage($"Found animation file {path}. Loading data...");
                    scene.Merge(FormatIdentifier.IdentifyAndOpen(path, model.Skeleton));
                }
                else
                {
                    context.Logger.LogMessage($"Couldn't find animation file {path}!");
                }
            }

            foreach (var animation in ImportSkeletalAnimations(scene))
            {
                rootBone.Animations.Add(animation.Name, animation);
            }

            foreach (var animation in ImportMaterialAnimations(scene))
            {
                _rootNode.Children.Add(animation);
            }

            return(_rootNode);
        }
Пример #17
0
        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;
        }
        BitmapContent Convert <T>(PixelBitmapContent <Color> bitmap) where T : struct, IPackedVector, IPackedVector <ushort>, IEquatable <T>
        {
            int w = bitmap.Width;
            int h = bitmap.Height;

            byte[] srcData = bitmap.GetPixelData();
            // BlockCopy only works on simple datatypes, not structs
            uint[] color = new uint[w * h];
            Buffer.BlockCopy(srcData, 0, color, 0, srcData.Length);
            int index = 0;

            ushort[] dest = new ushort[w * h];
            switch (DitherMethod)
            {
            case DitherMethod.None:
                foreach (uint i in color)
                {
                    // Convert the uint to a Color
                    Color c = new Color();
                    c.PackedValue = i;
                    Vector4 oldPixel = c.ToVector4();
                    if (PremultiplyAlpha)
                    {
                        // Set dest to the pre-multiplied value
                        oldPixel.X = oldPixel.X * oldPixel.W;
                        oldPixel.Y = oldPixel.Y * oldPixel.W;
                        oldPixel.Z = oldPixel.Z * oldPixel.W;
                    }
                    T d = new T();
                    // PackFromVector4 will convert to the destination format
                    d.PackFromVector4(oldPixel);
                    dest[index++] = d.PackedValue;
                }
                break;

            case DitherMethod.FloydSteinberg:
                // Create a copy of the entire bitmap in Vector4 format
                Vector4[] src = new Vector4[w * h];
                foreach (uint i in color)
                {
                    Color c = new Color();
                    c.PackedValue = i;
                    src[index++]  = c.ToVector4();
                }
                color = null;

                index = 0;
                for (int y = 0; y < h; ++y)
                {
                    for (int x = 0; x < w; ++x)
                    {
                        Vector4 oldPixel = src[index];

                        // Clamp to make sure the distributed errors don't overflow the valid range for colours
                        oldPixel.X = MathHelper.Clamp(oldPixel.X, 0, 1);
                        oldPixel.Y = MathHelper.Clamp(oldPixel.Y, 0, 1);
                        oldPixel.Z = MathHelper.Clamp(oldPixel.Z, 0, 1);
                        oldPixel.W = MathHelper.Clamp(oldPixel.W, 0, 1);

                        T d = new T();
                        d.PackFromVector4(oldPixel);
                        Vector4 newPixel = d.ToVector4();

                        // Distribute the error ahead and below the current pixel
                        //
                        // +------+------+------+
                        // |      |pixel | 7/16 |
                        // +------+------+------+
                        // | 3/16 | 5/16 | 1/16 |
                        // +------+------+------+

                        Vector4 quantError = oldPixel - newPixel;
                        if (x < (w - 1))
                        {
                            src[index + 1] = src[index + 1] + (quantError * (7.0f / 16.0f));
                            if (y < (h - 1))
                            {
                                src[index + w + 1] = src[index + w + 1] + (quantError * (1.0f / 16.0f));
                            }
                        }
                        if (y < (h - 1))
                        {
                            if (x > 0)
                            {
                                src[index + w - 1] = src[index + w - 1] + (quantError * (3.0f / 16.0f));
                            }
                            src[index + w] = src[index + w] + (quantError * (5.0f / 16.0f));
                        }

                        if (PremultiplyAlpha)
                        {
                            // Set dest to the pre-multiplied value
                            newPixel.X = newPixel.X * newPixel.W;
                            newPixel.Y = newPixel.Y * newPixel.W;
                            newPixel.Z = newPixel.Z * newPixel.W;
                        }

                        // PackFromVector4 will convert to the destination format
                        d.PackFromVector4(newPixel);
                        dest[index] = d.PackedValue;

                        ++index;
                    }
                }
                break;
            }
            PixelBitmapContent <T> result = new PixelBitmapContent <T>(w, h);

            byte[] destData = new byte[w * h * 2];
            Buffer.BlockCopy(dest, 0, destData, 0, destData.Length);
            result.SetPixelData(destData);
            return(result);
        }
Пример #19
0
        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));
        }
Пример #20
0
		// 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
			};
		}
Пример #21
0
        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]);
        }
        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]);
        }
Пример #23
0
        public override SpriteFontContent Process(FontDescription input,
                                                  ContentProcessorContext context)
        {
            var output = new SpriteFontContent(input);
            var font   = new Font(input.FontName, input.Size);

            // Make sure that this font is installed on the system.
            // Creating a font object with a font that's not contained will default to MS Sans Serif:
            // http://msdn.microsoft.com/en-us/library/zet4c3fa.aspx
            if (font.FontFamily.Name == "Microsoft Sans Serif" && input.FontName != "Microsoft Sans Serif")
            {
                throw new PipelineException(string.Format("Font {0} is not installed on this computer.", input.FontName));
            }

            var estimatedSurfaceArea = 0;
            var largestHeight        = 0;
            var widthsAndHeights     = new List <Point>();

            // Estimate the bounds of each rect to calculate the
            // final texture size
            var sf = StringFormat.GenericTypographic;

            sf.Trimming    = StringTrimming.None;
            sf.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

            using (var bmp = new Bitmap((int)(font.Size), (int)(font.Size)))
                using (var temp = System.Drawing.Graphics.FromImage(bmp))
                {
                    // Calculate and save the size of each character
                    foreach (var ch in input.Characters)
                    {
                        var charSize = temp.MeasureString(ch.ToString(), font, new PointF(0, 0), sf);
                        var width    = (int)charSize.Width;
                        var height   = (int)charSize.Height;

                        estimatedSurfaceArea += width;
                        largestHeight         = Math.Max(largestHeight, height);

                        widthsAndHeights.Add(new Point(width, height));
                    }

                    // TODO: Using the largest height will give us some empty space
                    // This can be optimized to pack a smaller texture if necessary
                    estimatedSurfaceArea *= largestHeight;
                }

            output.VerticalLineSpacing = largestHeight;

            // calculate the best height and width for our output texture.
            // TODO: GetMonoGamePlatform()
            var texBounds = calculateOutputTextureBounds(estimatedSurfaceArea, true);

            // Create our texture
            var outputBitmap = new Bitmap(texBounds.X, texBounds.Y);

            using (var g = System.Drawing.Graphics.FromImage(outputBitmap))
            {
                g.FillRectangle(Brushes.Transparent, new System.Drawing.Rectangle(0, 0, outputBitmap.Width, outputBitmap.Height));

                int x = 0;
                int y = 0;
                // Draw each glyph into the image.
                for (int i = 0; i < input.Characters.Count; i++)
                {
                    var kernData  = FontHelper.GetCharWidthABC(input.Characters[i], font, g);
                    int charWidth = (int)(Math.Abs(kernData.abcA) + kernData.abcB + kernData.abcC);

                    if (!input.UseKerning)
                    {
                        charWidth = (int)kernData.abcB;
                    }

                    if (x + charWidth >= texBounds.X)
                    {
                        x  = 0;
                        y += largestHeight;
                    }

                    Rectangle rect = new Microsoft.Xna.Framework.Rectangle(x, y, charWidth, widthsAndHeights[i].Y);
                    output.Glyphs.Add(rect);

                    // Characters with a negative a kerning value (like j) need to be adjusted,
                    // so (in the case of j) the bottom curve doesn't render outside our source
                    // rect.
                    var renderPoint = new PointF(x, y);
                    if (kernData.abcA < 0)
                    {
                        renderPoint.X += Math.Abs(kernData.abcA);
                    }

                    g.DrawString(input.Characters[i].ToString(), font, Brushes.White, renderPoint, sf);
                    output.Cropping.Add(new Rectangle(0, 0, charWidth, output.Glyphs[i].Height));

                    if (!input.UseKerning)
                    {
                        kernData.abcA = 0;
                        kernData.abcC = 0;
                    }
                    output.Kerning.Add(new Vector3(kernData.abcA, kernData.abcB, kernData.abcC));

                    // Add a 2 pixel spacing between characters
                    x += charWidth + 2;
                }

                // Drawing against a transparent black background blends
                // the 'alpha' pixels against black, leaving a black outline.
                // Interpolate between black and white
                // based on it's intensity to covert this 'outline' to
                // it's grayscale equivalent.
                var transBlack = Color.TransparentBlack;
                for (var i = 0; i < outputBitmap.Width; i++)
                {
                    for (var j = 0; j < outputBitmap.Height; j++)
                    {
                        var px = outputBitmap.GetPixel(i, j);

                        if (px.ColorsEqual(transBlack))
                        {
                            continue;
                        }

                        var val = (px.R + px.B + px.G) / (255.0f * 3.0f);
                        var col = Color.Lerp(Color.Transparent, Color.White, val);
                        px = System.Drawing.Color.FromArgb(col.A, col.R, col.G, col.B);
                        outputBitmap.SetPixel(i, j, px);
                    }
                }

                var bitmapContent = new PixelBitmapContent <Color>(texBounds.X, texBounds.Y);
                bitmapContent.SetPixelData(outputBitmap.GetData());
                output.Texture.Faces.Add(new MipmapChain(bitmapContent));
            }

            return(output);
        }
Пример #24
0
        /// <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 ext = Path.GetExtension(filename).ToLower();

            // Special case for loading some formats
            switch (ext)
            {
            case ".dds":
                return(DdsLoader.Import(filename, context));

            case ".bmp":
                return(LoadImage(filename));
            }

            var output = new Texture2DContent {
                Identity = new ContentIdentity(filename)
            };

            FREE_IMAGE_FORMAT format = FREE_IMAGE_FORMAT.FIF_UNKNOWN;
            var fBitmap = FreeImage.LoadEx(filename, FREE_IMAGE_LOAD_FLAGS.DEFAULT, ref format);

            //if freeimage can not recognize the image type
            if (format == FREE_IMAGE_FORMAT.FIF_UNKNOWN)
            {
                throw new ContentLoadException("TextureImporter failed to load '" + filename + "'");
            }
            //if freeimage can recognize the file headers but can't read its contents
            else if (fBitmap.IsNull)
            {
                throw new InvalidContentException("TextureImporter couldn't understand the contents of '" + filename + "'", output.Identity);
            }
            BitmapContent face   = null;
            var           height = (int)FreeImage.GetHeight(fBitmap);
            var           width  = (int)FreeImage.GetWidth(fBitmap);
            //uint bpp = FreeImage.GetBPP(fBitmap);
            var imageType = FreeImage.GetImageType(fBitmap);

            // Swizzle channels and expand to include an alpha channel
            fBitmap = ConvertAndSwapChannels(fBitmap, imageType);

            // The bits per pixel and image type may have changed
            uint bpp = FreeImage.GetBPP(fBitmap);

            imageType = FreeImage.GetImageType(fBitmap);
            var pitch     = (int)FreeImage.GetPitch(fBitmap);
            var redMask   = FreeImage.GetRedMask(fBitmap);
            var greenMask = FreeImage.GetGreenMask(fBitmap);
            var blueMask  = FreeImage.GetBlueMask(fBitmap);

            // Create the byte array for the data
            byte[] bytes = new byte[((width * height * bpp - 1) / 8) + 1];

            //Converts the pixel data to bytes, do not try to use this call to switch the color channels because that only works for 16bpp bitmaps
            FreeImage.ConvertToRawBits(bytes, fBitmap, pitch, bpp, redMask, greenMask, blueMask, true);
            // Create the Pixel bitmap content depending on the image type
            switch (imageType)
            {
            //case FREE_IMAGE_TYPE.FIT_BITMAP:
            default:
                face = new PixelBitmapContent <Color>(width, height);
                break;

            case FREE_IMAGE_TYPE.FIT_RGBA16:
                face = new PixelBitmapContent <Rgba64>(width, height);
                break;

            case FREE_IMAGE_TYPE.FIT_RGBAF:
                face = new PixelBitmapContent <Vector4>(width, height);
                break;
            }
            FreeImage.UnloadEx(ref fBitmap);

            face.SetPixelData(bytes);
            output.Faces[0].Add(face);
            return(output);
        }
Пример #25
0
        public override FontContent Process(FontSource input, ContentProcessorContext context)
        {
            List <char> codePoints           = new List <char>(input.CodePoints);
            int         localeCodePointCount = codePoints.Count;

            // Ensure ASCII characters [33..126] code points are in the processed
            for (byte cp = 33; cp < 127; cp++)
            {
                if (codePoints.FindIndex(delegate(char c) { return(c == cp); }) == -1)
                {
                    codePoints.Add((char)cp);
                }
            }
            context.Logger.LogMessage("Processing {0} ({1} total) code points for font {1}", localeCodePointCount, codePoints.Count, input.Name);
#if DEBUG
            StringBuilder sb = new StringBuilder(input.CodePoints.Length);
            foreach (char c in codePoints)
            {
                sb.AppendFormat("{0}", c);
            }
            Console.WriteLine(sb.ToString());
#endif
            GdiFont font = new GdiFont(input.Name, 20, FontStyle.Regular, GraphicsUnit.Pixel);

            // Use the fonts (pseudo) EM square
            Size emSquare = TextRenderer.MeasureText("M", font);
            context.Logger.LogMessage("EM Square: {0}x{1}; {2}", emSquare.Width, emSquare.Height, font.Height);
            context.Logger.LogMessage("=> {0}x{1}", 256.0f / (float)emSquare.Width, 256.0f / (float)emSquare.Height);

            Bitmap bmp = new Bitmap(256, 256, PixelFormat.Format32bppArgb);
            Dictionary <char, BnoerjGlyph> glyphs = new Dictionary <char, BnoerjGlyph>(codePoints.Count);

            Graphics g = Graphics.FromImage(bmp);
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;

            if (CheckFontForEmbedding(g, font, context) == false)
            {
                context.Logger.LogWarning("No help link",
                                          new ContentIdentity("definition.locale", "LocaleContent", "Font"),
                                          "Font {1} may not be embedded.", font.FontFamily);
            }

            TextFormatFlags textFlags    = TextFormatFlags.Left | TextFormatFlags.Bottom | TextFormatFlags.NoPadding | TextFormatFlags.GlyphOverhangPadding;
            Size            proposedSize = new Size(int.MaxValue, int.MaxValue);
            int             x            = 0;
            int             y            = 0;
            int             usedArea     = 0;
            foreach (char c in codePoints)
            {
                Size size = TextRenderer.MeasureText(g, c.ToString(), font, proposedSize, textFlags);
                if (x + size.Width > bmp.Width)
                {
                    x  = 0;
                    y += font.Height;
                }
                GdiRect rc = new GdiRect(x, y, size.Width, size.Height);
                TextRenderer.DrawText(g, c.ToString(), font, rc, GdiColor.White, GdiColor.Black, textFlags);

                BnoerjGlyph glyph = new BnoerjGlyph();
                glyph.Bounds = new XnaRect(x, y, size.Width, size.Height);
                glyphs.Add(c, glyph);

                x += size.Width;

                usedArea += size.Width * size.Height;
            }

            // Draw a font height square in the lower right corner
            x = bmp.Width - font.Height;
            y = bmp.Height - font.Height;
            g.FillRectangle(Brushes.White, x, y, font.Height, font.Height);

            context.Logger.LogMessage("Font efficiency: Using {0:p} of texture area", (float)usedArea / (float)(bmp.Width * bmp.Height));

            SortedDictionary <uint, int> kerningPairs = GetKerningPairs(g, font, glyphs, context);

            PixelBitmapContent <XnaColor> texture = new PixelBitmapContent <XnaColor>(256, 256);
            GdiRect    srcRect    = new GdiRect(0, 0, bmp.Width, bmp.Height);
            BitmapData bmpData    = bmp.LockBits(srcRect, ImageLockMode.WriteOnly, bmp.PixelFormat);
            int        bytes      = bmp.Width * bmp.Height * 4;
            byte[]     bgraValues = new byte[bytes];
            System.Runtime.InteropServices.Marshal.Copy(bmpData.Scan0, bgraValues, 0, bytes);
            bmp.UnlockBits(bmpData);

            // Set bitmap data to white and the alpha to its luminance value
            for (int i = 0; i < bytes; i += 4)
            {
                float l = (float)bgraValues[i + 2] * 0.312713f +
                          (float)bgraValues[i + 1] * 0.329016f +
                          (float)bgraValues[i + 0] * 0.358271f;
                bgraValues[i + 3] = (byte)l;
                bgraValues[i + 2] = 255;                 // red
                bgraValues[i + 1] = 255;                 // green
                bgraValues[i + 0] = 255;                 // blue
            }

            texture.SetPixelData(bgraValues);
            return(new FontContent(texture, font.Height, glyphs, kerningPairs));
        }