public override TextureContent Process(TextureContent input, ContentProcessorContext context) { SurfaceFormat format; if (input.Faces[0][0].TryGetFormat(out format)) { // If it is already a compressed format, we cannot do anything else so just return it if (format.IsCompressedFormat()) { return(input); } } if (ColorKeyEnabled || ResizeToPowerOfTwo || MakeSquare || PremultiplyAlpha) { // Convert to floating point format for modifications. Keep the original format for conversion back later on if required. var originalType = input.Faces[0][0].GetType(); try { input.ConvertBitmapType(typeof(PixelBitmapContent <Vector4>)); } catch (Exception ex) { context.Logger.LogImportantMessage("Could not convert input texture for processing. " + ex.ToString()); throw ex; } for (int f = 0; f < input.Faces.Count; ++f) { var face = input.Faces[f]; for (int m = 0; m < face.Count; ++m) { var bmp = (PixelBitmapContent <Vector4>)face[m]; if (ColorKeyEnabled) { bmp.ReplaceColor(ColorKeyColor.ToVector4(), Vector4.Zero); } if (ResizeToPowerOfTwo) { if (!GraphicsUtil.IsPowerOfTwo(bmp.Width) || !GraphicsUtil.IsPowerOfTwo(bmp.Height) || (MakeSquare && bmp.Height != bmp.Width)) { var newWidth = GraphicsUtil.GetNextPowerOfTwo(bmp.Width); var newHeight = GraphicsUtil.GetNextPowerOfTwo(bmp.Height); if (MakeSquare) { newWidth = newHeight = Math.Max(newWidth, newHeight); } var resized = new PixelBitmapContent <Vector4>(newWidth, newHeight); BitmapContent.Copy(bmp, resized); bmp = resized; } } else if (MakeSquare && bmp.Height != bmp.Width) { var newSize = Math.Max(bmp.Width, bmp.Height); var resized = new PixelBitmapContent <Vector4>(newSize, newSize); BitmapContent.Copy(bmp, resized); } if (PremultiplyAlpha) { for (int y = 0; y < bmp.Height; ++y) { var row = bmp.GetRow(y); for (int x = 0; x < bmp.Width; ++x) { row[x] = Color.FromNonPremultiplied(row[x]).ToVector4(); } } } face[m] = bmp; } } // If no change to the surface format was desired, change it back now before it early outs if (TextureFormat == TextureProcessorOutputFormat.NoChange) { input.ConvertBitmapType(originalType); } } // Get the texture profile for the platform and let it convert the texture. var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); texProfile.ConvertTexture(context, input, TextureFormat, GenerateMipmaps, false); return(input); }
public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) { var output = new SpriteFontContent(input); var fontName = input.FontName; #if WINDOWS || LINUX #if WINDOWS var windowsfolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows); var fontDirectory = Path.Combine(windowsfolder, "Fonts"); fontName = FindFontFileFromFontName(fontName, fontDirectory); #elif LINUX fontName = FindFontFileFromFontName(fontName, input.Style.ToString()); #endif if (string.IsNullOrWhiteSpace(fontName)) { fontName = input.FontName; #endif var directory = Path.GetDirectoryName(input.Identity.SourceFilename); List <string> directories = new List <string>(); directories.Add(directory); directories.Add("/Library/Fonts"); #if WINDOWS directories.Add(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 || LINUX } #endif context.Logger.LogMessage("Building Font {0}", fontName); // Get the platform specific texture profile. var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); try { if (!File.Exists(fontName)) { throw new Exception(string.Format("Could not load {0}", fontName)); } var lineSpacing = 0f; int yOffsetMin = 0; var glyphs = ImportFont(input, out lineSpacing, out yOffsetMin, context, fontName); // Optimize. foreach (Glyph glyph in glyphs) { GlyphCropper.Crop(glyph); } // We need to know how to pack the glyphs. bool requiresPot, requiresSquare; texProfile.Requirements(context, TextureFormat, out requiresPot, out requiresSquare); var face = GlyphPacker.ArrangeGlyphs(glyphs, requiresPot, requiresSquare); // Adjust line and character spacing. lineSpacing += input.Spacing; output.VerticalLineSpacing = (int)lineSpacing; foreach (var glyph in glyphs) { output.CharacterMap.Add(glyph.Character); var texRect = new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, glyph.Subrect.Height); output.Glyphs.Add(texRect); var cropping = new Rectangle(0, (int)(glyph.YOffset - yOffsetMin), (int)glyph.XAdvance, output.VerticalLineSpacing); output.Cropping.Add(cropping); // Set the optional character kerning. if (input.UseKerning) { output.Kerning.Add(new Vector3(glyph.CharacterWidths.A, glyph.CharacterWidths.B, glyph.CharacterWidths.C)); } else { output.Kerning.Add(new Vector3(0, texRect.Width, 0)); } } output.Texture.Faces[0].Add(face); } catch (Exception ex) { context.Logger.LogImportantMessage("{0}", ex.ToString()); } // Perform the final texture conversion. texProfile.ConvertTexture(context, output.Texture, TextureFormat, false, true); return(output); }
public override SpriteFontContent Process( FontDescription input, ContentProcessorContext context) { string fontFile = FindFont(input.FontName, input.Style.ToString()); if (string.IsNullOrWhiteSpace(fontFile)) { var directories = new List <string> { Path.GetDirectoryName(input.Identity.SourceFilename) }; // Add special per platform directories if (PlatformInfo.CurrentOS == PlatformInfo.OS.Windows) { directories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts")); } else if (PlatformInfo.CurrentOS == PlatformInfo.OS.MacOSX) { directories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Fonts")); directories.Add("/Library/Fonts"); directories.Add("/System/Library/Fonts/Supplemental"); } foreach (var dir in directories) { foreach (var ext in _fontExtensions) { fontFile = Path.Combine(dir, input.FontName + ext); if (File.Exists(fontFile)) { break; } } if (File.Exists(fontFile)) { break; } } } if (!File.Exists(fontFile)) { throw new FileNotFoundException("Could not find \"" + input.FontName + "\" font file."); } context.Logger.LogMessage("Building Font {0}", fontFile); // Get the platform specific texture profile. var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); if (!File.Exists(fontFile)) { throw new Exception(string.Format("Could not load {0}", fontFile)); } var glyphs = ImportFont(input, out float lineSpacing, out int yOffsetMin, context, fontFile); // Optimize. foreach (Glyph glyph in glyphs) { GlyphCropper.Crop(glyph); } texProfile.Requirements(context, TextureFormat, out bool requiresPot, out bool requiresSquare); var output = new SpriteFontContent(input); var face = GlyphPacker.ArrangeGlyphs(glyphs, requiresPot, requiresSquare); output.Texture.Faces[0].Add(face); // Adjust line and character spacing. lineSpacing += input.Spacing; output.VerticalLineSpacing = (int)lineSpacing; foreach (var glyph in glyphs) { output.CharacterMap.Add(glyph.Character); var texRegion = new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, glyph.Subrect.Height); output.Regions.Add(texRegion); output.Croppings.Add( new Rectangle(0, (int)(glyph.YOffset - yOffsetMin), (int)glyph.XAdvance, output.VerticalLineSpacing)); // Set the optional character kerning. output.Kerning.Add(input.UseKerning ? new Vector3(glyph.CharacterWidths.A, glyph.CharacterWidths.B, glyph.CharacterWidths.C) : new Vector3(0, texRegion.Width, 0)); } var facePixels = face.GetPixelSpan(); if (PremultiplyAlpha) { for (int i = 0; i < facePixels.Length; i++) { ref Color pixel = ref facePixels[i]; // A is the value of white alpha we want pixel.R = pixel.A; pixel.G = pixel.A; pixel.B = pixel.A; } }
public override SpriteFontContent Process(FontDescription input, ContentProcessorContext context) { var output = new SpriteFontContent(input); var fontFile = FindFont(input.FontName, input.Style.ToString()); if (string.IsNullOrWhiteSpace(fontFile)) { var directories = new List <string> { Path.GetDirectoryName(input.Identity.SourceFilename) }; var extensions = new string[] { "", ".ttf", ".ttc", ".otf" }; // Add special per platform directories if (CurrentPlatform.OS == OS.Windows) { directories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Fonts")); } else if (CurrentPlatform.OS == OS.MacOSX) { directories.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library", "Fonts")); directories.Add("/Library/Fonts"); } foreach (var dir in directories) { foreach (var ext in extensions) { fontFile = Path.Combine(dir, input.FontName + ext); if (File.Exists(fontFile)) { break; } } if (File.Exists(fontFile)) { break; } } } if (!File.Exists(fontFile)) { throw new FileNotFoundException("Could not find \"" + input.FontName + "\" font file."); } context.Logger.LogMessage("Building Font {0}", fontFile); // Get the platform specific texture profile. var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); { if (!File.Exists(fontFile)) { throw new Exception(string.Format("Could not load {0}", fontFile)); } var lineSpacing = 0f; int yOffsetMin = 0; var glyphs = ImportFont(input, out lineSpacing, out yOffsetMin, context, fontFile); // Optimize. foreach (Glyph glyph in glyphs) { GlyphCropper.Crop(glyph); } // We need to know how to pack the glyphs. bool requiresPot, requiresSquare; texProfile.Requirements(context, TextureFormat, out requiresPot, out requiresSquare); var face = GlyphPacker.ArrangeGlyphs(glyphs, requiresPot, requiresSquare); // Adjust line and character spacing. lineSpacing += input.Spacing; output.VerticalLineSpacing = (int)lineSpacing; foreach (var glyph in glyphs) { output.CharacterMap.Add(glyph.Character); var texRect = new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, glyph.Subrect.Height); output.Glyphs.Add(texRect); var cropping = new Rectangle(0, (int)(glyph.YOffset - yOffsetMin), (int)glyph.XAdvance, output.VerticalLineSpacing); output.Cropping.Add(cropping); // Set the optional character kerning. if (input.UseKerning) { output.Kerning.Add(new Vector3(glyph.CharacterWidths.A, glyph.CharacterWidths.B, glyph.CharacterWidths.C)); } else { output.Kerning.Add(new Vector3(0, texRect.Width, 0)); } } output.Texture.Faces[0].Add(face); } if (PremultiplyAlpha) { var bmp = output.Texture.Faces[0][0]; var data = bmp.GetPixelData(); var idx = 0; for (; idx < data.Length;) { var r = data[idx]; // Special case of simply copying the R component into the A, since R is the value of white alpha we want data[idx + 0] = r; data[idx + 1] = r; data[idx + 2] = r; data[idx + 3] = r; idx += 4; } bmp.SetPixelData(data); } else { var bmp = output.Texture.Faces[0][0]; var data = bmp.GetPixelData(); var idx = 0; for (; idx < data.Length;) { var r = data[idx]; // Special case of simply moving the R component into the A and setting RGB to solid white, since R is the value of white alpha we want data[idx + 0] = 255; data[idx + 1] = 255; data[idx + 2] = 255; data[idx + 3] = r; idx += 4; } bmp.SetPixelData(data); } // Perform the final texture conversion. texProfile.ConvertTexture(context, output.Texture, TextureFormat, true); return(output); }
public override SpriteFontContent Process(Texture2DContent input, ContentProcessorContext context) { // extract the glyphs from the texture and map them to a list of characters. // we need to call GtCharacterForIndex for each glyph in the Texture to // get the char for that glyph, by default we start at ' ' then '!' and then ASCII // after that. BitmapContent face = input.Faces[0][0]; face.TryGetFormat(out SurfaceFormat faceFormat); if (faceFormat != SurfaceFormat.Rgba32) { var colorFace = new PixelBitmapContent <Color>(face.Width, face.Height); BitmapContent.Copy(face, colorFace); face = colorFace; } var output = new SpriteFontContent(); var glyphs = ExtractGlyphs((PixelBitmapContent <Color>)face); // Optimize. foreach (var glyph in glyphs) { GlyphCropper.Crop(glyph); output.VerticalLineSpacing = Math.Max(output.VerticalLineSpacing, glyph.Subrect.Height); } // Get the platform specific texture profile. var texProfile = TextureProfile.ForPlatform(context.TargetPlatform); texProfile.Requirements(context, TextureFormat, out bool requiresPot, out bool requiresSquare); face = GlyphPacker.ArrangeGlyphs(glyphs, requiresPot, requiresSquare); foreach (var glyph in glyphs) { output.CharacterMap.Add(glyph.Character); output.Regions.Add( new Rectangle(glyph.Subrect.X, glyph.Subrect.Y, glyph.Subrect.Width, glyph.Subrect.Height)); output.Croppings.Add( new Rectangle((int)glyph.XOffset, (int)glyph.YOffset, glyph.Width, glyph.Height)); var abc = glyph.CharacterWidths; output.Kerning.Add(new Vector3(abc.A, abc.B, abc.C)); } output.Texture.Faces[0].Add(face); var bmp = output.Texture.Faces[0][0]; if (PremultiplyAlpha) { var data = bmp.GetPixelData(); var idx = 0; for (; idx < data.Length;) { var r = data[idx + 0]; var g = data[idx + 1]; var b = data[idx + 2]; var a = data[idx + 3]; var col = Color.FromNonPremultiplied(r, g, b, a); data[idx + 0] = col.R; data[idx + 1] = col.G; data[idx + 2] = col.B; data[idx + 3] = col.A; idx += 4; } bmp.SetPixelData(data); } // Perform the final texture conversion. texProfile.ConvertTexture(context, output.Texture, TextureFormat, true); return(output); }