From cd316d2ca1f90d50623674190c4ca72e07fae9af Mon Sep 17 00:00:00 2001 From: 0auBSQ <58159635+0auBSQ@users.noreply.github.com> Date: Wed, 2 Oct 2024 00:56:12 +0900 Subject: [PATCH] Support color tags on vertical texts (gradiant works only with horizontal text) --- .../04.Graphics/TextRenderer/CFontRenderer.cs | 39 ++++++++++- .../TextRenderer/CSkiaSharpTextRenderer.cs | 4 +- .../04.Graphics/TextRenderer/ITextRenderer.cs | 5 ++ OpenTaiko/src/Helpers/ObjectExtensions.cs | 67 +++++++++++++++++++ .../05.DaniSelect/CActSelect段位リスト.cs | 8 +-- 5 files changed, 115 insertions(+), 8 deletions(-) diff --git a/FDK/src/04.Graphics/TextRenderer/CFontRenderer.cs b/FDK/src/04.Graphics/TextRenderer/CFontRenderer.cs index e586c72a..3d898b11 100644 --- a/FDK/src/04.Graphics/TextRenderer/CFontRenderer.cs +++ b/FDK/src/04.Graphics/TextRenderer/CFontRenderer.cs @@ -2,7 +2,7 @@ using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; using SkiaSharp; - +using static FDK.CSkiaSharpTextRenderer; using Color = System.Drawing.Color; namespace FDK { @@ -144,6 +144,42 @@ namespace FDK { //グラデ(全体)にも対応したいですね? + List tokens = new List(); + tokens = this.textRenderer.Tokenize(drawstr, fontColor, edgeColor, secondEdgeColor, gradationTopColor, gradationBottomColor); + + string purified = this.textRenderer.Purify(drawstr); + string[] strList = new string[purified.Length]; + for (int i = 0; i < purified.Length; i++) + strList[i] = purified.Substring(i, 1); + SKBitmap[] strImageList = new SKBitmap[purified.Length]; + + int nWidth = 0; + int nHeight = 0; + int _idx = 0; + foreach (SStringToken tok in tokens) { + string[] splitted = new string[tok.s.Length]; + for (int i = 0; i < tok.s.Length; i++) + splitted[i] = tok.s.Substring(i, 1); + + for (int i = 0; i < splitted.Length; i++) { + strImageList[_idx] = this.textRenderer.DrawText(splitted[i], drawmode, tok.TextColor, tok.OutlineColor, secondEdgeColor, tok.GradiantTop, tok.GradiantBottom, edge_Ratio, false); + + //回転する文字 + if (Rotate_Chara_List_Vertical.Contains(splitted[i])) { + using (var surface = new SKCanvas(strImageList[_idx])) { + surface.RotateDegrees(90, strImageList[_idx].Width / 2, strImageList[_idx].Height / 2); + surface.DrawBitmap(strImageList[_idx], 0, 0); + } + } + + nWidth = Math.Max(nWidth, strImageList[_idx].Width); + nHeight += strImageList[_idx].Height - 25; + _idx++; + } + } + + + /* string[] strList = new string[drawstr.Length]; for (int i = 0; i < drawstr.Length; i++) strList[i] = drawstr.Substring(i, 1); @@ -166,6 +202,7 @@ namespace FDK { nWidth = Math.Max(nWidth, strImageList[i].Width); nHeight += strImageList[i].Height - 25; } + */ SKImageInfo skImageInfo = new SKImageInfo(nWidth, nHeight); diff --git a/FDK/src/04.Graphics/TextRenderer/CSkiaSharpTextRenderer.cs b/FDK/src/04.Graphics/TextRenderer/CSkiaSharpTextRenderer.cs index 06606dd5..5e4a7dab 100644 --- a/FDK/src/04.Graphics/TextRenderer/CSkiaSharpTextRenderer.cs +++ b/FDK/src/04.Graphics/TextRenderer/CSkiaSharpTextRenderer.cs @@ -77,11 +77,11 @@ namespace FDK { private const string TagRegex = @"<(/?)([gc](?:\.#[0-9a-fA-F]{6})*?)>"; - private string Purify(string input) { + public string Purify(string input) { return Regex.Replace(input, TagRegex, ""); } - private List Tokenize(string input, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor) { + public List Tokenize(string input, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor) { List tokens = new List(); Stack tags = new Stack(); Stack tokenStack = new Stack(); diff --git a/FDK/src/04.Graphics/TextRenderer/ITextRenderer.cs b/FDK/src/04.Graphics/TextRenderer/ITextRenderer.cs index 4b0c1c39..3e4947db 100644 --- a/FDK/src/04.Graphics/TextRenderer/ITextRenderer.cs +++ b/FDK/src/04.Graphics/TextRenderer/ITextRenderer.cs @@ -1,8 +1,13 @@ using SkiaSharp; +using static FDK.CSkiaSharpTextRenderer; using Color = System.Drawing.Color; namespace FDK { internal interface ITextRenderer : IDisposable { SKBitmap DrawText(string drawstr, CFontRenderer.DrawMode drawmode, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor, int edge_Ratio, bool keepCenter); + + string Purify(string input); + + List Tokenize(string input, Color fontColor, Color edgeColor, Color? secondEdgeColor, Color gradationTopColor, Color gradationBottomColor); } } diff --git a/OpenTaiko/src/Helpers/ObjectExtensions.cs b/OpenTaiko/src/Helpers/ObjectExtensions.cs index f7270ace..3f50e1c8 100644 --- a/OpenTaiko/src/Helpers/ObjectExtensions.cs +++ b/OpenTaiko/src/Helpers/ObjectExtensions.cs @@ -115,6 +115,73 @@ namespace System { private const string TagRegex = @"<(/?)([gc](?:\.#[0-9a-fA-F]{6})*?)>"; + public static string TrimStringWithTags(this string input, int maxLength) { + // This will store the result + string result = string.Empty; + // This will store the length of characters outside tags + int count = 0; + + // Stack to keep track of open tags + Stack openTags = new Stack(); + + // Use regex to match tags and content + var regex = new Regex(TagRegex); + var matches = regex.Matches(input); + int lastIndex = 0; + + foreach (Match match in matches) { + // Add the characters before the current match (which are non-tag characters) + if (match.Index > lastIndex) { + // Get the substring before the tag + string contentBeforeTag = input.Substring(lastIndex, match.Index - lastIndex); + + // Calculate how many characters we can take from this content + int charsToTake = Math.Min(maxLength - count, contentBeforeTag.Length); + + // Append the allowed part to the result + result += contentBeforeTag.Substring(0, charsToTake); + + // Update the count of characters outside tags + count += charsToTake; + + // If we have reached the max length, break + if (count >= maxLength) { + break; + } + } + + // Process the tag + result += match.Value; + + // If it's an opening tag, push it to the stack + if (!match.Value.StartsWith(" 0) { + // If it's a closing tag, pop the corresponding opening tag from the stack + openTags.Pop(); + } + + // Update the last index after the tag + lastIndex = match.Index + match.Length; + } + + // If there is remaining text after the last tag, handle it + if (lastIndex < input.Length && count < maxLength) { + string remainingContent = input.Substring(lastIndex); + result += remainingContent.Substring(0, Math.Min(maxLength - count, remainingContent.Length)); + } + + // Close all remaining open tags + while (openTags.Count > 0) { + string openTag = openTags.Pop(); + // Convert the opening tag to its closing counterpart + string tagName = new Regex(@"<([gc](?:\.#[0-9a-fA-F]{6})*?)>").Match(openTag).Groups[1].Value; + result += $""; + } + + return result; + } + public static string RemoveTags(this string input) { return Regex.Replace(input, TagRegex, ""); } diff --git a/OpenTaiko/src/Stages/05.DaniSelect/CActSelect段位リスト.cs b/OpenTaiko/src/Stages/05.DaniSelect/CActSelect段位リスト.cs index 9784450e..ed56180d 100644 --- a/OpenTaiko/src/Stages/05.DaniSelect/CActSelect段位リスト.cs +++ b/OpenTaiko/src/Stages/05.DaniSelect/CActSelect段位リスト.cs @@ -1,8 +1,6 @@ -using System; -using System.Drawing; +using System.Drawing; using FDK; using Silk.NET.Maths; -using static OpenTaiko.CActSelect曲リスト; using Rectangle = System.Drawing.Rectangle; namespace OpenTaiko { @@ -336,7 +334,7 @@ namespace OpenTaiko { titleTmp = stNode.ttkタイトル[stNode.ttkタイトル.Length - 1].str; } - TitleTextureKey ttkTmp = new TitleTextureKey(titleTmp.Substring(0, 2), pfDanPlateTitle, Color.White, Color.Black, 1000); + TitleTextureKey ttkTmp = new TitleTextureKey(titleTmp.TrimStringWithTags(2), pfDanPlateTitle, Color.White, Color.Black, 1000); TitleTextureKey.ResolveTitleTextureTate(ttkTmp).t2D中心基準描画(x + OpenTaiko.Skin.DaniSelect_DanPlateTitle_Offset[0], y + OpenTaiko.Skin.DaniSelect_DanPlateTitle_Offset[1]); } } @@ -718,7 +716,7 @@ namespace OpenTaiko { } // Two char header, will be used for grade unlocking too - string tmp = song.ldTitle.GetString("").Substring(0, 2); + string tmp = song.ldTitle.GetString("").TrimStringWithTags(2); stバー情報[i].ttkタイトル[listSongs[i].DanSongs.Count] = new TitleTextureKey(tmp, pfDanSong, Color.Black, Color.Transparent, 700);