From 17ed82fc3ccb141dcba6d5b07b53e977562a8e79 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Wed, 22 Dec 2021 12:46:17 +0100 Subject: [PATCH] Generify GenericFont's string drawing --- CHANGELOG.md | 3 + MLEM.Extended/Font/GenericBitmapFont.cs | 12 +--- MLEM.Extended/Font/GenericStashFont.cs | 16 ++--- MLEM/Font/GenericFont.cs | 79 ++++++++++++++++++++++++- MLEM/Font/GenericSpriteFont.cs | 12 +--- Sandbox/GameImpl.cs | 42 ++++++++++++- 6 files changed, 130 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42fb798..c020eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ Jump to version: - [5.0.0](#500) ## 5.3.0 (Unreleased) +### MLEM +Improvements +- Generify GenericFont's string drawing ## 5.2.0 ### MLEM diff --git a/MLEM.Extended/Font/GenericBitmapFont.cs b/MLEM.Extended/Font/GenericBitmapFont.cs index 922f6e7..db785b4 100644 --- a/MLEM.Extended/Font/GenericBitmapFont.cs +++ b/MLEM.Extended/Font/GenericBitmapFont.cs @@ -1,4 +1,3 @@ -using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Font; @@ -38,14 +37,9 @@ namespace MLEM.Extended.Font { return region != null ? new Vector2(region.XAdvance, region.Height).X : 0; } - /// - public override void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { - batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth); - } - - /// - public override void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { - batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth); + /// + protected override void DrawChar(SpriteBatch batch, char c, string cString, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { + batch.DrawString(this.Font, cString, position, color, rotation, origin, scale, effects, layerDepth); } } diff --git a/MLEM.Extended/Font/GenericStashFont.cs b/MLEM.Extended/Font/GenericStashFont.cs index 42d9d41..4afb137 100644 --- a/MLEM.Extended/Font/GenericStashFont.cs +++ b/MLEM.Extended/Font/GenericStashFont.cs @@ -1,4 +1,3 @@ -using System.Text; using FontStashSharp; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -33,20 +32,15 @@ namespace MLEM.Extended.Font { this.Italic = italic != null ? new GenericStashFont(italic) : this; } - /// - public override void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { - this.Font.DrawText(batch, text, position, color, scale, rotation, origin, layerDepth); - } - - /// - public override void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { - this.Font.DrawText(batch, text, position, color, scale, rotation, origin, layerDepth); - } - /// protected override float MeasureChar(char c) { return this.Font.MeasureString(c.ToCachedString()).X; } + /// + protected override void DrawChar(SpriteBatch batch, char c, string cString, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { + this.Font.DrawText(batch, cString, position, color, scale, rotation, origin, layerDepth); + } + } } \ No newline at end of file diff --git a/MLEM/Font/GenericFont.cs b/MLEM/Font/GenericFont.cs index 97e23aa..8ea788b 100644 --- a/MLEM/Font/GenericFont.cs +++ b/MLEM/Font/GenericFont.cs @@ -54,11 +54,26 @@ namespace MLEM.Font { /// The width of the given character with the default scale protected abstract float MeasureChar(char c); - /// - public abstract void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth); + /// + /// Draws the given character with the given data for use in . + /// Note that this method is only called internally. + /// + /// The sprite batch to draw with. + /// The character which will be drawn. + /// A string representation of the character which will be drawn. + /// The drawing location on screen. + /// A color mask. + /// A rotation of this character. + /// Center of the rotation. 0,0 by default. + /// A scaling of this character. + /// Modificators for drawing. Can be combined. + /// A depth of the layer of this character. + protected abstract void DrawChar(SpriteBatch batch, char c, string cString, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth); /// - public abstract void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth); + public void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { + this.DrawString(batch, text.ToString(), position, color, rotation, origin, scale, effects, layerDepth); + } /// public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects effects, float layerDepth) { @@ -80,6 +95,64 @@ namespace MLEM.Font { this.DrawString(batch, text, position, color, 0, Vector2.Zero, Vector2.One, SpriteEffects.None, 0); } + /// + public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { + var (flipX, flipY) = Vector2.Zero; + var flippedV = (effects & SpriteEffects.FlipVertically) != 0; + var flippedH = (effects & SpriteEffects.FlipHorizontally) != 0; + if (flippedV || flippedH) { + var (w, h) = this.MeasureString(text); + if (flippedH) { + origin.X *= -1; + flipX = -w; + } + if (flippedV) { + origin.Y *= -1; + flipY = this.LineHeight - h; + } + } + + var trans = Matrix.Identity; + if (rotation == 0) { + trans.M11 = flippedH ? -scale.X : scale.X; + trans.M22 = flippedV ? -scale.Y : scale.Y; + trans.M41 = (flipX - origin.X) * trans.M11 + position.X; + trans.M42 = (flipY - origin.Y) * trans.M22 + position.Y; + } else { + var sin = (float) Math.Sin(rotation); + var cos = (float) Math.Cos(rotation); + trans.M11 = (flippedH ? -scale.X : scale.X) * cos; + trans.M12 = (flippedH ? -scale.X : scale.X) * sin; + trans.M21 = (flippedV ? -scale.Y : scale.Y) * -sin; + trans.M22 = (flippedV ? -scale.Y : scale.Y) * cos; + trans.M41 = (flipX - origin.X) * trans.M11 + (flipY - origin.Y) * trans.M21 + position.X; + trans.M42 = (flipX - origin.X) * trans.M12 + (flipY - origin.Y) * trans.M22 + position.Y; + } + + var offset = Vector2.Zero; + for (var i = 0; i < text.Length; i++) { + var c = text[i]; + if (c == '\n') { + offset.X = 0; + offset.Y += this.LineHeight; + continue; + } + + var cString = c.ToCachedString(); + var (cW, cH) = this.MeasureString(cString); + + var charPos = offset; + if (flippedH) + charPos.X += cW; + if (flippedV) + charPos.Y += cH - this.LineHeight; + Vector2.Transform(ref charPos, ref trans, out charPos); + + this.DrawChar(batch, c, cString, charPos, color, rotation, Vector2.Zero, scale, effects, layerDepth); + offset.X += cW; + } + } + /// /// Measures the width of the given string when drawn with this font's underlying font. /// This method uses internally to calculate the size of known characters and calculates additional characters like , and . diff --git a/MLEM/Font/GenericSpriteFont.cs b/MLEM/Font/GenericSpriteFont.cs index 7634796..9f29567 100644 --- a/MLEM/Font/GenericSpriteFont.cs +++ b/MLEM/Font/GenericSpriteFont.cs @@ -1,5 +1,4 @@ using System.Linq; -using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using MLEM.Extensions; @@ -37,14 +36,9 @@ namespace MLEM.Font { return this.Font.MeasureString(c.ToCachedString()).X; } - /// - public override void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { - batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth); - } - - /// - public override void DrawString(SpriteBatch batch, StringBuilder text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { - batch.DrawString(this.Font, text, position, color, rotation, origin, scale, effects, layerDepth); + /// + protected override void DrawChar(SpriteBatch batch, char c, string cString, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { + batch.DrawString(this.Font, cString, position, color, rotation, origin, scale, effects, layerDepth); } private static SpriteFont SetDefaults(SpriteFont font) { diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index 3354521..76cce39 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -239,7 +239,7 @@ namespace Sandbox { par.OnDrawn = (e, time, batch, a) => batch.DrawRectangle(e.DisplayArea.ToExtended(), Color.Red); this.UiSystem.Add("Load", loadGroup);*/ - var spillPanel = new Panel(Anchor.Center, new Vector2(100), Vector2.Zero); + /*var spillPanel = new Panel(Anchor.Center, new Vector2(100), Vector2.Zero); var squishingGroup = spillPanel.AddChild(new SquishingGroup(Anchor.TopLeft, Vector2.One)); squishingGroup.AddChild(new Button(Anchor.TopLeft, new Vector2(30), "TL") { OnUpdated = (e, time) => e.IsHidden = Input.IsKeyDown(Keys.D1), @@ -266,7 +266,45 @@ namespace Sandbox { e.SetAreaDirty(); } }).SetData("Ref", "Main"); - this.UiSystem.Add("SpillTest", spillPanel); + this.UiSystem.Add("SpillTest", spillPanel);*/ + + var regularFont = spriteFont.Font; + var genericFont = spriteFont; + + var index = 0; + var pos = new Vector2(100, 20); + var scale = 1F; + var origin = Vector2.Zero; + var rotation = 0F; + var effects = SpriteEffects.None; + + this.OnDraw += (g, time) => { + const string testString = "This is a\ntest string\n\twith long lines.\nLet's write some more stuff. Let's\r\nsplit lines weirdly."; + if (Input.IsKeyPressed(Keys.I)) { + index++; + if (index == 1) { + scale = 2; + } else if (index == 2) { + origin = new Vector2(15, 15); + } else if (index == 3) { + rotation = 0.25F; + } else if (index == 4) { + effects = SpriteEffects.FlipHorizontally; + } else if (index == 5) { + effects = SpriteEffects.FlipVertically; + } else if (index == 6) { + effects = SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically; + } + } + + this.SpriteBatch.Begin(); + if (Input.IsKeyDown(Keys.LeftShift)) { + this.SpriteBatch.DrawString(regularFont, testString, pos, Color.Red, rotation, origin, scale, effects, 0); + } else { + genericFont.DrawString(this.SpriteBatch, testString, pos, Color.Green, rotation, origin, scale, effects, 0); + } + this.SpriteBatch.End(); + }; } protected override void DoUpdate(GameTime gameTime) {