using System; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Xml; using Quik; using Quik.Typography; namespace QuikTestApplication { public class TestFont : QuikFont { public override QuikFontStyle Style => _style; private static QuikFontStyle _style; private static HashSet _characters = new HashSet(); private static Dictionary _glyphs = new Dictionary(); public static byte[] TextureData { get; private set; } = Array.Empty(); public static QuikVec2 TextureSize { get; private set; } public QuikTexture Texture { get; } public override float Ascender => throw new NotImplementedException(); public override float Descender => throw new NotImplementedException(); public TestFont(QuikContext context) { Texture = context.TextureManager.CreateTexture(TextureSize, false, QuikImageFormat.RgbaU8); unsafe { fixed (byte* ptr = &TextureData[0]) { Texture.Image((IntPtr)ptr, QuikImageFormat.RgbaU8, TextureSize, 0); } } } static TestFont() { using (Stream str = typeof(TestFont).Assembly.GetManifestResourceStream("QuikTestApplication.font.xml")) { XmlDocument document = new XmlDocument(); document.Load(str); string family = document.DocumentElement.Attributes["name"].Value; float fontSize = float.Parse(document.DocumentElement.Attributes["size"].Value); QuikFontType style = QuikFontType.Normal; if (document.DocumentElement.Attributes["bold"].Value == "true") style = QuikFontType.Bold; if (document.DocumentElement.Attributes["italic"].Value == "true") style = QuikFontType.Italic; _style = new QuikFontStyle(family, fontSize, style); QuikVec2 atlasSize = default; atlasSize.X = float.Parse(document.DocumentElement.Attributes["width"].Value); atlasSize.Y = float.Parse(document.DocumentElement.Attributes["height"].Value); TextureSize = atlasSize; foreach (XmlElement element in document.SelectNodes("/font/character")) { QuikRectangle UVs; QuikVec2 origin; float advance; int chr = element.Attributes["text"].Value[0]; QuikVec2 pos; QuikVec2 size; pos.X = float.Parse(element.Attributes["x"].Value); pos.Y = float.Parse(element.Attributes["y"].Value); size.X = float.Parse(element.Attributes["width"].Value); size.Y = float.Parse(element.Attributes["height"].Value); UVs = new QuikRectangle( (pos.X + size.X)/atlasSize.X, pos.Y/atlasSize.Y, pos.X/atlasSize.X, (size.Y + pos.Y)/atlasSize.Y); origin.X = float.Parse(element.Attributes["origin-x"].Value); origin.Y = float.Parse(element.Attributes["origin-y"].Value); advance = float.Parse(element.Attributes["advance"].Value); QuikGlyph glyph = new QuikGlyph(chr, UVs, size, origin, default, new QuikVec2(advance, 0)); _glyphs.Add(chr, glyph); _characters.Add(chr); } } using (Stream str = typeof(TestFont).Assembly.GetManifestResourceStream("QuikTestApplication.font.dat")) { TextureData = new byte[(int)str.Length]; str.Read(TextureData, 0, (int)str.Length); } // Evil pointer stuff. Beware! Span head = MemoryMarshal.Cast(TextureData); for (int i = 0; i < head.Length; i++) { if (head[i] == 0xff000000) { head[i] = 0x00000000; } } } public override bool HasCharacter(int character) { return _characters.Contains((char) character); } public override void GetCharacter(int character, out QuikTexture texture, out QuikGlyph glyph) { if (!_glyphs.TryGetValue(character, out glyph)) { glyph = _glyphs['?']; } texture = Texture; } } }