From 9a03a8c62d4bf178d5bc92f7c04adb50f0981803 Mon Sep 17 00:00:00 2001 From: Ellpeck Date: Wed, 10 Apr 2024 20:27:00 +0200 Subject: [PATCH] Added the ability for formatted (tokenized) strings to be drawn with custom rotation, origin and flipping Closes #18 --- CHANGELOG.md | 8 +- Demos/TextFormattingDemo.cs | 9 ++- MLEM.Extended/Font/GenericBitmapFont.cs | 2 +- MLEM.Extended/Font/GenericStashFont.cs | 2 +- MLEM.Ui/Elements/Paragraph.cs | 2 +- MLEM/Font/GenericFont.cs | 97 +++++++++++++------------ MLEM/Font/GenericSpriteFont.cs | 2 +- MLEM/Formatting/Codes/Code.cs | 4 +- MLEM/Formatting/Codes/ImageCode.cs | 6 +- MLEM/Formatting/Codes/LinkCode.cs | 4 +- MLEM/Formatting/Codes/OutlineCode.cs | 7 +- MLEM/Formatting/Codes/ShadowCode.cs | 5 +- MLEM/Formatting/Codes/SubSupCode.cs | 4 +- MLEM/Formatting/Codes/UnderlineCode.cs | 7 +- MLEM/Formatting/Codes/WobblyCode.cs | 5 +- MLEM/Formatting/Token.cs | 11 +-- MLEM/Formatting/TokenizedString.cs | 21 ++++-- Sandbox/GameImpl.cs | 70 +++++++++--------- build.cake | 2 +- 19 files changed, 148 insertions(+), 120 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c71bcf..eb13ca4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ MLEM tries to adhere to [semantic versioning](https://semver.org/). Potentially breaking changes are written in **bold**. Jump to version: -- [6.3.2](#632-in-development) +- [7.0.0](#700-in-development) - [6.3.1](#631) - [6.3.0](#630) - [6.2.0](#620) @@ -13,7 +13,11 @@ Jump to version: - [5.1.0](#510) - [5.0.0](#500) -## 6.3.2 (In Development) +## 7.0.0 (In Development) + +### MLEM +Additions +- **Added the ability for formatted (tokenized) strings to be drawn with custom rotation, origin and flipping** ### MLEM.Ui Additions diff --git a/Demos/TextFormattingDemo.cs b/Demos/TextFormattingDemo.cs index 1d32021..4c128bd 100644 --- a/Demos/TextFormattingDemo.cs +++ b/Demos/TextFormattingDemo.cs @@ -27,6 +27,7 @@ namespace Demos { private TokenizedString tokenizedText; private GenericFont font; private bool drawBounds; + private bool transform; private float Scale { get { // calculate our scale based on how much larger the window is, so that the text scales with the window @@ -85,7 +86,11 @@ namespace Demos { } // draw the text itself (start and end indices are optional) - this.tokenizedText.Draw(time, this.SpriteBatch, pos, this.font, Color.White, this.Scale, 0, this.startIndex, this.endIndex); + this.tokenizedText.Draw(time, this.SpriteBatch, pos, this.font, Color.White, this.Scale, 0, + this.transform ? 0.25F : 0, + this.transform ? new Vector2(size.X / this.Scale, 128) : Vector2.Zero, + this.transform ? SpriteEffects.FlipHorizontally : SpriteEffects.None, + this.startIndex, this.endIndex); this.SpriteBatch.End(); } @@ -97,6 +102,8 @@ namespace Demos { // change some demo showcase info based on keybinds if (this.InputHandler.IsPressed(Keys.B)) this.drawBounds = !this.drawBounds; + if (this.InputHandler.IsPressed(Keys.T)) + this.transform = !this.transform; if (this.startIndex > 0 && this.InputHandler.IsDown(Keys.Left)) this.startIndex--; if (this.startIndex < this.tokenizedText.String.Length && this.InputHandler.IsDown(Keys.Right)) diff --git a/MLEM.Extended/Font/GenericBitmapFont.cs b/MLEM.Extended/Font/GenericBitmapFont.cs index d1ff2c4..5caf097 100644 --- a/MLEM.Extended/Font/GenericBitmapFont.cs +++ b/MLEM.Extended/Font/GenericBitmapFont.cs @@ -38,7 +38,7 @@ namespace MLEM.Extended.Font { } /// - protected override void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) { + public override void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) { batch.DrawString(this.Font, character, position, color, rotation, Vector2.Zero, scale, effects, layerDepth); } diff --git a/MLEM.Extended/Font/GenericStashFont.cs b/MLEM.Extended/Font/GenericStashFont.cs index 961e13e..8f1a612 100644 --- a/MLEM.Extended/Font/GenericStashFont.cs +++ b/MLEM.Extended/Font/GenericStashFont.cs @@ -47,7 +47,7 @@ namespace MLEM.Extended.Font { } /// - protected override void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) { + public override void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) { this.Font.DrawText(batch, character, position, color, rotation, Vector2.Zero, scale, layerDepth, this.CharacterSpacing, this.LineSpacing); } diff --git a/MLEM.Ui/Elements/Paragraph.cs b/MLEM.Ui/Elements/Paragraph.cs index 3560f56..80a3245 100644 --- a/MLEM.Ui/Elements/Paragraph.cs +++ b/MLEM.Ui/Elements/Paragraph.cs @@ -246,7 +246,7 @@ namespace MLEM.Ui.Elements { var pos = this.DisplayArea.Location + new Vector2(this.GetAlignmentOffset(), 0); var sc = this.TextScale * this.TextScaleMultiplier * this.Scale; var color = this.TextColor.OrDefault(Color.White) * alpha; - this.TokenizedText.Draw(time, batch, pos, this.RegularFont, color, sc, 0, this.DrawStartIndex, this.DrawEndIndex); + this.TokenizedText.Draw(time, batch, pos, this.RegularFont, color, sc, 0, 0, Vector2.Zero, SpriteEffects.None, this.DrawStartIndex, this.DrawEndIndex); base.Draw(time, batch, alpha, context); } diff --git a/MLEM/Font/GenericFont.cs b/MLEM/Font/GenericFont.cs index 75de4e9..711fc40 100644 --- a/MLEM/Font/GenericFont.cs +++ b/MLEM/Font/GenericFont.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using MLEM.Formatting; +using MLEM.Formatting.Codes; using MLEM.Misc; namespace MLEM.Font { @@ -59,7 +61,7 @@ namespace MLEM.Font { /// /// Draws the given code point with the given data for use in . - /// Note that this method is only called internally. + /// Note that this method should only be called internally for rendering of more complex strings, like in implementations. /// /// The sprite batch to draw with. /// The code point which will be drawn. @@ -70,7 +72,7 @@ namespace MLEM.Font { /// A scaling of this character. /// Modificators for drawing. Can be combined. /// A depth of the layer of this character. - protected abstract void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth); + public abstract void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth); /// public void DrawString(SpriteBatch batch, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { @@ -174,6 +176,52 @@ namespace MLEM.Font { return GenericFont.SplitStringSeparate(Enumerable.Repeat(new DecoratedCodePointSource(new CodePointSource(text), this, 0), 1), width, scale).First(); } + public Matrix CalculateStringTransform(Vector2 position, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, Vector2 flipSize) { + var (flipX, flipY) = (0F, 0F); + var flippedV = (effects & SpriteEffects.FlipVertically) != 0; + var flippedH = (effects & SpriteEffects.FlipHorizontally) != 0; + if (flippedV || flippedH) { + if (flippedH) { + origin.X *= -1; + flipX = -flipSize.X; + } + if (flippedV) { + origin.Y *= -1; + flipY = this.LineHeight - flipSize.Y; + } + } + + 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; + } + return trans; + } + + public Vector2 MoveFlipped(Vector2 charPos, SpriteEffects effects, Vector2 charSize) { + if ((effects & SpriteEffects.FlipHorizontally) != 0) + charPos.X += charSize.X; + if ((effects & SpriteEffects.FlipVertically) != 0) + charPos.Y += charSize.Y - this.LineHeight; + return charPos; + } + + public Vector2 TransformSingleCharacter(Vector2 stringPos, Vector2 charPosOffset, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { + return Vector2.Transform(this.MoveFlipped(charPosOffset, effects, charSize), this.CalculateStringTransform(stringPos, rotation, origin, scale, effects, stringSize)); + } + private Vector2 MeasureString(CodePointSource text, bool ignoreTrailingSpaces) { var size = Vector2.Zero; if (text.Length <= 0) @@ -220,7 +268,7 @@ namespace MLEM.Font { private void DrawString(SpriteBatch batch, CodePointSource text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth) { var flipSize = effects != SpriteEffects.None ? this.MeasureString(text, false) : Vector2.Zero; - var trans = this.CalculateStringTransform(position, rotation, origin, scale, flipSize, effects); + var trans = this.CalculateStringTransform(position, rotation, origin, scale, effects, flipSize); var offset = Vector2.Zero; var index = 0; @@ -232,14 +280,7 @@ namespace MLEM.Font { } else { var character = CodePointSource.ToString(codePoint); var charSize = this.MeasureString(character); - - var charPos = offset; - if ((effects & SpriteEffects.FlipHorizontally) != 0) - charPos.X += charSize.X; - if ((effects & SpriteEffects.FlipVertically) != 0) - charPos.Y += charSize.Y - this.LineHeight; - charPos = Vector2.Transform(charPos, trans); - + var charPos = Vector2.Transform(this.MoveFlipped(offset, effects, charSize), trans); this.DrawCharacter(batch, codePoint, character, charPos, color, rotation, scale, effects, layerDepth); offset.X += charSize.X; } @@ -367,40 +408,6 @@ namespace MLEM.Font { } } - internal Matrix CalculateStringTransform(Vector2 position, float rotation, Vector2 origin, Vector2 scale, Vector2 flipSize, SpriteEffects effects) { - var (flipX, flipY) = (0F, 0F); - var flippedV = (effects & SpriteEffects.FlipVertically) != 0; - var flippedH = (effects & SpriteEffects.FlipHorizontally) != 0; - if (flippedV || flippedH) { - if (flippedH) { - origin.X *= -1; - flipX = -flipSize.X; - } - if (flippedV) { - origin.Y *= -1; - flipY = this.LineHeight - flipSize.Y; - } - } - - 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; - } - return trans; - } - private static bool IsTrailingSpace(CodePointSource s, int index) { while (index < s.Length) { var (codePoint, length) = s.GetCodePoint(index); diff --git a/MLEM/Font/GenericSpriteFont.cs b/MLEM/Font/GenericSpriteFont.cs index 9dee912..4357408 100644 --- a/MLEM/Font/GenericSpriteFont.cs +++ b/MLEM/Font/GenericSpriteFont.cs @@ -39,7 +39,7 @@ namespace MLEM.Font { } /// - protected override void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) { + public override void DrawCharacter(SpriteBatch batch, int codePoint, string character, Vector2 position, Color color, float rotation, Vector2 scale, SpriteEffects effects, float layerDepth) { batch.DrawString(this.Font, character, position, color, rotation, Vector2.Zero, scale, effects, layerDepth); } diff --git a/MLEM/Formatting/Codes/Code.cs b/MLEM/Formatting/Codes/Code.cs index 393b149..2969105 100644 --- a/MLEM/Formatting/Codes/Code.cs +++ b/MLEM/Formatting/Codes/Code.cs @@ -92,12 +92,12 @@ namespace MLEM.Formatting.Codes { } /// - public virtual bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) { + public virtual bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, Vector2 stringPos, ref Vector2 charPosOffset, GenericFont font, ref Color color, ref Vector2 scale, ref float rotation, ref Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { return false; } /// - public virtual void DrawSelf(GameTime time, SpriteBatch batch, Token token, Vector2 pos, GenericFont font, Color color, float scale, float depth) {} + public virtual void DrawSelf(GameTime time, SpriteBatch batch, Token token, Vector2 stringPos, Vector2 charPosOffset, GenericFont font, Color color, Vector2 scale, float rotation, Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize) {} /// /// Creates a new formatting code from the given regex and regex match. diff --git a/MLEM/Formatting/Codes/ImageCode.cs b/MLEM/Formatting/Codes/ImageCode.cs index 0b51d6c..3a7cd2d 100644 --- a/MLEM/Formatting/Codes/ImageCode.cs +++ b/MLEM/Formatting/Codes/ImageCode.cs @@ -36,9 +36,11 @@ namespace MLEM.Formatting.Codes { } /// - public override void DrawSelf(GameTime time, SpriteBatch batch, Token token, Vector2 pos, GenericFont font, Color color, float scale, float depth) { + public override void DrawSelf(GameTime time, SpriteBatch batch, Token token, Vector2 stringPos, Vector2 charPosOffset, GenericFont font, Color color, Vector2 scale, float rotation, Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize) { var actualColor = this.copyTextColor ? color : Color.White.CopyAlpha(color); - batch.Draw(this.image.CurrentRegion, new RectangleF(pos, new Vector2(font.LineHeight * scale)), actualColor); + var size = new Vector2(font.LineHeight); + var finalPos = font.TransformSingleCharacter(stringPos, charPosOffset, rotation, origin, scale, effects, stringSize, size); + batch.Draw(this.image.CurrentRegion, new RectangleF(finalPos, size * scale), actualColor, rotation, Vector2.Zero, effects, 0); } } diff --git a/MLEM/Formatting/Codes/LinkCode.cs b/MLEM/Formatting/Codes/LinkCode.cs index 618d63a..84cef42 100644 --- a/MLEM/Formatting/Codes/LinkCode.cs +++ b/MLEM/Formatting/Codes/LinkCode.cs @@ -40,9 +40,9 @@ namespace MLEM.Formatting.Codes { } /// - public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) { + public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, Vector2 stringPos, ref Vector2 charPosOffset, GenericFont font, ref Color color, ref Vector2 scale, ref float rotation, ref Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { // since we inherit from UnderlineCode, we can just call base if selected - return this.IsSelected() && base.DrawCharacter(time, batch, codePoint, character, token, indexInToken, ref pos, font, ref color, ref scale, depth); + return this.IsSelected() && base.DrawCharacter(time, batch, codePoint, character, token, indexInToken, stringPos, ref charPosOffset, font, ref color, ref scale, ref rotation, ref origin, depth, effects, stringPos, charSize); } } diff --git a/MLEM/Formatting/Codes/OutlineCode.cs b/MLEM/Formatting/Codes/OutlineCode.cs index 026ffdd..e5cb6d7 100644 --- a/MLEM/Formatting/Codes/OutlineCode.cs +++ b/MLEM/Formatting/Codes/OutlineCode.cs @@ -22,10 +22,11 @@ namespace MLEM.Formatting.Codes { } /// - public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) { + public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, Vector2 stringPos, ref Vector2 charPosOffset, GenericFont font, ref Color color, ref Vector2 scale, ref float rotation, ref Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { foreach (var dir in this.diagonals ? Direction2Helper.AllExceptNone : Direction2Helper.Adjacent) { - var offset = Vector2.Normalize(dir.Offset().ToVector2()) * (this.thickness * scale); - font.DrawString(batch, character, pos + offset, this.color.CopyAlpha(color), 0, Vector2.Zero, scale, SpriteEffects.None, depth); + var offset = Vector2.Normalize(dir.Offset().ToVector2()) * this.thickness; + var finalPos = font.TransformSingleCharacter(stringPos, charPosOffset + offset, rotation, origin, scale, effects, stringSize, charSize); + font.DrawString(batch, character, finalPos, this.color.CopyAlpha(color), rotation, Vector2.Zero, scale, effects, depth); } return false; } diff --git a/MLEM/Formatting/Codes/ShadowCode.cs b/MLEM/Formatting/Codes/ShadowCode.cs index 217af03..bf849e8 100644 --- a/MLEM/Formatting/Codes/ShadowCode.cs +++ b/MLEM/Formatting/Codes/ShadowCode.cs @@ -18,8 +18,9 @@ namespace MLEM.Formatting.Codes { } /// - public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) { - font.DrawString(batch, character, pos + this.offset * scale, this.color.CopyAlpha(color), 0, Vector2.Zero, scale, SpriteEffects.None, depth); + public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, Vector2 stringPos, ref Vector2 charPosOffset, GenericFont font, ref Color color, ref Vector2 scale, ref float rotation, ref Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { + var finalPos = font.TransformSingleCharacter(stringPos, charPosOffset + this.offset, rotation, origin, scale, effects, stringSize, charSize); + font.DrawString(batch, character, finalPos, this.color.CopyAlpha(color), rotation, Vector2.Zero, scale, effects, depth); // we return false since we still want regular drawing to occur return false; } diff --git a/MLEM/Formatting/Codes/SubSupCode.cs b/MLEM/Formatting/Codes/SubSupCode.cs index a39f4a4..874a6b2 100644 --- a/MLEM/Formatting/Codes/SubSupCode.cs +++ b/MLEM/Formatting/Codes/SubSupCode.cs @@ -15,8 +15,8 @@ namespace MLEM.Formatting.Codes { } /// - public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) { - pos.Y += this.offset * font.LineHeight * scale; + public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, Vector2 stringPos, ref Vector2 charPosOffset, GenericFont font, ref Color color, ref Vector2 scale, ref float rotation, ref Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { + charPosOffset.Y += this.offset * font.LineHeight * scale.Y; return false; } diff --git a/MLEM/Formatting/Codes/UnderlineCode.cs b/MLEM/Formatting/Codes/UnderlineCode.cs index c5fa08f..4f1f5b1 100644 --- a/MLEM/Formatting/Codes/UnderlineCode.cs +++ b/MLEM/Formatting/Codes/UnderlineCode.cs @@ -19,13 +19,12 @@ namespace MLEM.Formatting.Codes { } /// - public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) { + public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, Vector2 stringPos, ref Vector2 charPosOffset, GenericFont font, ref Color color, ref Vector2 scale, ref float rotation, ref Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { // don't underline spaces at the end of lines if (codePoint == ' ' && token.DisplayString.Length > indexInToken + 1 && token.DisplayString[indexInToken + 1] == '\n') return false; - var size = font.MeasureString(character) * scale; - var t = size.Y * this.thickness; - batch.Draw(batch.GetBlankTexture(), new RectangleF(pos.X, pos.Y + this.yOffset * size.Y - t, size.X, t), color); + var finalPos = font.TransformSingleCharacter(stringPos, charPosOffset + new Vector2(0, (this.yOffset - this.thickness) * charSize.Y), rotation, origin, scale, effects, stringSize, charSize); + batch.Draw(batch.GetBlankTexture(), new RectangleF(finalPos.X, finalPos.Y, charSize.X * scale.X, this.thickness * charSize.Y * scale.Y), null, color, rotation, Vector2.Zero, SpriteEffects.None, depth); return false; } diff --git a/MLEM/Formatting/Codes/WobblyCode.cs b/MLEM/Formatting/Codes/WobblyCode.cs index 4d02d21..cdc7536 100644 --- a/MLEM/Formatting/Codes/WobblyCode.cs +++ b/MLEM/Formatting/Codes/WobblyCode.cs @@ -28,9 +28,8 @@ namespace MLEM.Formatting.Codes { } /// - public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) { - var offset = new Vector2(0, (float) Math.Sin(token.Index + indexInToken + this.TimeIntoAnimation.TotalSeconds * this.modifier) * font.LineHeight * this.heightModifier * scale); - pos += offset; + public override bool DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, Token token, int indexInToken, Vector2 stringPos, ref Vector2 charPosOffset, GenericFont font, ref Color color, ref Vector2 scale, ref float rotation, ref Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { + charPosOffset += new Vector2(0, (float) Math.Sin(token.Index + indexInToken + this.TimeIntoAnimation.TotalSeconds * this.modifier) * font.LineHeight * this.heightModifier * scale.Y); // we return false since we still want regular drawing to occur, we just changed the position return false; } diff --git a/MLEM/Formatting/Token.cs b/MLEM/Formatting/Token.cs index 518f466..ccca36d 100644 --- a/MLEM/Formatting/Token.cs +++ b/MLEM/Formatting/Token.cs @@ -109,9 +109,9 @@ namespace MLEM.Formatting { /// The color to draw with /// The scale to draw at /// The depth to draw at - public void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) { + public void DrawSelf(GameTime time, SpriteBatch batch, Vector2 stringPos, Vector2 charPosOffset, GenericFont font, Color color, Vector2 scale, float rotation, Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize) { foreach (var code in this.AppliedCodes) - code.DrawSelf(time, batch, this, pos, font, color, scale, depth); + code.DrawSelf(time, batch, this, stringPos, charPosOffset, font, color, scale, rotation, origin, depth, effects, stringSize); } /// @@ -127,14 +127,15 @@ namespace MLEM.Formatting { /// The color to draw with /// The scale to draw at /// The depth to draw at - public void DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, int indexInToken, Vector2 pos, GenericFont font, Color color, float scale, float depth) { + public void DrawCharacter(GameTime time, SpriteBatch batch, int codePoint, string character, int indexInToken, Vector2 stringPos, Vector2 charPosOffset, GenericFont font, Color color, Vector2 scale, float rotation, Vector2 origin, float depth, SpriteEffects effects, Vector2 stringSize, Vector2 charSize) { foreach (var code in this.AppliedCodes) { - if (code.DrawCharacter(time, batch, codePoint, character, this, indexInToken, ref pos, font, ref color, ref scale, depth)) + if (code.DrawCharacter(time, batch, codePoint, character, this, indexInToken, stringPos, ref charPosOffset, font, ref color, ref scale, ref rotation, ref origin, depth, effects, stringSize, charSize)) return; } // if no code drew, we have to do it ourselves - font.DrawString(batch, character, pos, color, 0, Vector2.Zero, scale, SpriteEffects.None, depth); + var finalPos = font.TransformSingleCharacter(stringPos, charPosOffset, rotation, origin, scale, effects, stringSize, charSize); + font.DrawCharacter(batch, codePoint, character, finalPos, color, rotation, scale, effects, depth); } /// diff --git a/MLEM/Formatting/TokenizedString.cs b/MLEM/Formatting/TokenizedString.cs index f27317b..2729060 100644 --- a/MLEM/Formatting/TokenizedString.cs +++ b/MLEM/Formatting/TokenizedString.cs @@ -180,9 +180,13 @@ namespace MLEM.Formatting { return null; } + public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth, float rotation = 0, Vector2 origin = default, SpriteEffects effects = SpriteEffects.None, int? startIndex = null, int? endIndex = null) { + this.Draw(time, batch, pos, font, color, new Vector2(scale), depth, rotation, origin, effects, startIndex, endIndex); + } + /// - public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth, int? startIndex = null, int? endIndex = null) { - var innerOffset = new Vector2(this.initialInnerOffset * scale, 0); + public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, Vector2 scale, float depth, float rotation = 0, Vector2 origin = default, SpriteEffects effects = SpriteEffects.None, int? startIndex = null, int? endIndex = null) { + var innerOffset = new Vector2(this.initialInnerOffset, 0); for (var t = 0; t < this.Tokens.Length; t++) { var token = this.Tokens[t]; if (endIndex != null && token.Index >= endIndex) @@ -192,8 +196,8 @@ namespace MLEM.Formatting { var drawColor = token.GetColor(color); if (startIndex == null || token.Index >= startIndex) - token.DrawSelf(time, batch, pos + innerOffset, drawFont, drawColor, scale, depth); - innerOffset.X += token.GetSelfWidth(drawFont) * scale; + token.DrawSelf(time, batch, pos, innerOffset, drawFont, drawColor, scale, rotation, origin, depth, effects, this.area.Size); + innerOffset.X += token.GetSelfWidth(drawFont); var indexInToken = 0; for (var l = 0; l < token.SplitDisplayString.Length; l++) { @@ -205,19 +209,20 @@ namespace MLEM.Formatting { var (codePoint, length) = line.GetCodePoint(cpsIndex); var character = CodePointSource.ToString(codePoint); + var charSize = drawFont.MeasureString(character); if (startIndex == null || token.Index + indexInToken >= startIndex) - token.DrawCharacter(time, batch, codePoint, character, indexInToken, pos + innerOffset, drawFont, drawColor, scale, depth); + token.DrawCharacter(time, batch, codePoint, character, indexInToken, pos, innerOffset, drawFont, drawColor, scale, rotation, origin, depth, effects, this.area.Size, charSize); - innerOffset.X += drawFont.MeasureString(character).X * scale; + innerOffset.X += charSize.X; indexInToken += length; cpsIndex += length; } // only split at a new line, not between tokens! if (l < token.SplitDisplayString.Length - 1) { - innerOffset.X = token.InnerOffsets[l] * scale; - innerOffset.Y += drawFont.LineHeight * scale; + innerOffset.X = token.InnerOffsets[l]; + innerOffset.Y += drawFont.LineHeight; } } } diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs index 2204287..6bd56d5 100644 --- a/Sandbox/GameImpl.cs +++ b/Sandbox/GameImpl.cs @@ -257,43 +257,45 @@ public class GameImpl : MlemGame { }).SetData("Ref", "Main"); this.UiSystem.Add("SpillTest", spillPanel); - var regularFont = spriteFont.Font; - var genericFont = spriteFont; + 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; + 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 += (_, _) => { - 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 (MlemGame.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; - } - } + const string testString = "This is a\ntest string\n\twith long lines.\nLet's write some more stuff. Let's\r\nsplit lines weirdly."; + var formatted = formatter.Tokenize(genericFont, testString); - this.SpriteBatch.Begin(); - if (MlemGame.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(); - }; + this.OnDraw += (_, time) => { + if (MlemGame.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 (MlemGame.Input.IsKeyDown(Keys.LeftShift)) { + this.SpriteBatch.DrawString(regularFont, testString, pos, Color.Red, rotation, origin, scale, effects, 0); + } else { + formatted.Draw(time, this.SpriteBatch, pos, genericFont, Color.Green, scale, 0, rotation, origin, effects); + } + this.SpriteBatch.End(); + }; /*var viewport = new BoxingViewportAdapter(this.Window, this.GraphicsDevice, 1280, 720); var newPanel = new Panel(Anchor.TopLeft, new Vector2(200, 100), new Vector2(10, 10)); diff --git a/build.cake b/build.cake index a634eed..0066d9d 100644 --- a/build.cake +++ b/build.cake @@ -2,7 +2,7 @@ #tool dotnet:?package=docfx&version=2.75.3 // this is the upcoming version, for prereleases -var version = Argument("version", "6.3.2"); +var version = Argument("version", "7.0.0"); var target = Argument("target", "Default"); var gitRef = Argument("ref", "refs/heads/main"); var buildNum = Argument("buildNum", "");