From 526fccd2a73180630fb429e80b69cdf5a3eb2eb6 Mon Sep 17 00:00:00 2001 From: psyGamer Date: Sun, 27 Oct 2024 10:30:14 +0100 Subject: [PATCH] refactor(Studio): Migrate subpixel-indicator to Skia --- Studio/CelesteStudio/Editing/GameInfoPanel.cs | 29 ++++++++++++------- Studio/CelesteStudio/Editing/Theme.cs | 10 +++++-- Studio/CelesteStudio/FontManager.cs | 10 ++++--- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Studio/CelesteStudio/Editing/GameInfoPanel.cs b/Studio/CelesteStudio/Editing/GameInfoPanel.cs index e0c04d0c..09ef1fa7 100644 --- a/Studio/CelesteStudio/Editing/GameInfoPanel.cs +++ b/Studio/CelesteStudio/Editing/GameInfoPanel.cs @@ -1,17 +1,22 @@ using System; using System.Text; using CelesteStudio.Communication; +using CelesteStudio.Controls; using CelesteStudio.Data; +using CelesteStudio.Util; using Eto.Drawing; using Eto.Forms; +using SkiaSharp; using StudioCommunication.Util; using System.ComponentModel; namespace CelesteStudio.Editing; public sealed class GameInfo : Panel { - private sealed class SubpixelIndicator : Drawable { - protected override void OnPaint(PaintEventArgs e) { + private sealed class SubpixelIndicator : SkiaDrawable { + protected override void Draw(PaintEventArgs e, SKSurface surface, SKImageInfo imageInfo) { + surface.Canvas.Clear(); + var remainder = CommunicationWrapper.PlayerPositionRemainder; float subpixelLeft = (float)Math.Round(remainder.X + 0.5f, CommunicationWrapper.GameSettings.SubpixelIndicatorDecimals, MidpointRounding.AwayFromZero); @@ -19,7 +24,7 @@ protected override void OnPaint(PaintEventArgs e) { float subpixelRight = 1.0f - subpixelLeft; float subpixelBottom = 1.0f - subpixelTop; - var font = FontManager.StatusFont; + var font = FontManager.SKStatusFont; const float indicatorPadding = 8.0f; const float rectPadding = 5.0f; @@ -44,18 +49,22 @@ protected override void OnPaint(PaintEventArgs e) { string top = subpixelTop.ToFormattedString(vDecimals); string bottom = subpixelBottom.ToFormattedString(vDecimals); - e.Graphics.DrawText(font, Settings.Instance.Theme.StatusFg, x - rectPadding - font.MeasureWidth(left), y + (rectSize - textHeight) / 2.0f, left); - e.Graphics.DrawText(font, Settings.Instance.Theme.StatusFg, x + rectPadding + rectSize, y + (rectSize - textHeight) / 2.0f, right); + surface.Canvas.DrawText(left, x - rectPadding - font.MeasureWidth(left), y + (rectSize - textHeight) / 2.0f + font.Offset(), font, Settings.Instance.Theme.StatusFgPaint); + surface.Canvas.DrawText(right, x + rectPadding + rectSize, y + (rectSize - textHeight) / 2.0f + font.Offset(), font, Settings.Instance.Theme.StatusFgPaint); - e.Graphics.DrawText(font, Settings.Instance.Theme.StatusFg, x + (rectSize - font.MeasureWidth(top)) / 2.0f, y - rectPadding - textHeight, top); - e.Graphics.DrawText(font, Settings.Instance.Theme.StatusFg, x + (rectSize - font.MeasureWidth(bottom)) / 2.0f, y + rectPadding + rectSize, bottom); + surface.Canvas.DrawText(top, MathF.Round(x + (rectSize - font.MeasureWidth(top)) / 2.0f), MathF.Round(y - rectPadding - textHeight + font.Offset()), font, Settings.Instance.Theme.StatusFgPaint); + surface.Canvas.DrawText(bottom, x + (rectSize - font.MeasureWidth(bottom)) / 2.0f, y + rectPadding + rectSize + font.Offset(), font, Settings.Instance.Theme.StatusFgPaint); int boxThickness = Math.Max(1, (int)Math.Round(rectSize / 20.0f)); float dotThickness = boxThickness * 1.25f; - using var boxPen = new Pen(Settings.Instance.Theme.SubpixelIndicatorBox, boxThickness); - e.Graphics.DrawRectangle(boxPen, x, y, rectSize, rectSize); - e.Graphics.FillRectangle(Settings.Instance.Theme.SubpixelIndicatorDot, x + (rectSize - dotThickness) * subpixelLeft, y + (rectSize - dotThickness) * subpixelTop, dotThickness, dotThickness); + using var boxPaint = new SKPaint(); + boxPaint.ColorF = Settings.Instance.Theme.SubpixelIndicatorBox.ToSkia(); + boxPaint.Style = SKPaintStyle.Stroke; + boxPaint.StrokeWidth = boxThickness; + + surface.Canvas.DrawRect(x, y, rectSize, rectSize, boxPaint); + surface.Canvas.DrawRect(x + (rectSize - dotThickness) * subpixelLeft, y + (rectSize - dotThickness) * subpixelTop, dotThickness, dotThickness, Settings.Instance.Theme.SubpixelIndicatorDotPaint); Width = (int)((textWidth + rectPadding + indicatorPadding) * 2.0f + rectSize); Height = (int)((textHeight + rectPadding + indicatorPadding) * 2.0f + rectSize); diff --git a/Studio/CelesteStudio/Editing/Theme.cs b/Studio/CelesteStudio/Editing/Theme.cs index f88e050f..752cfda1 100644 --- a/Studio/CelesteStudio/Editing/Theme.cs +++ b/Studio/CelesteStudio/Editing/Theme.cs @@ -72,7 +72,7 @@ public struct Theme { // Cache SKPaints private StylePaint? _actionPaint, _anglePaint, _breakpointPaint, _savestateBreakpointPaint, _delimiter, _command, _frame, _comment; - private SKPaint? _commentBox, _popupMenuFgPaint, _popupMenuFgDisabledPaint, _popupMenuFgExtraPaint, _popupMenuBgPaint, _popupMenuSelectedPaint; + private SKPaint? _commentBox, _statusFgPaint, _subpixelIndicatorDotPaint, _popupMenuFgPaint, _popupMenuFgDisabledPaint, _popupMenuFgExtraPaint, _popupMenuBgPaint, _popupMenuSelectedPaint; public StylePaint ActionPaint => _actionPaint ??= Action.CreatePaint(); public StylePaint AnglePaint => _anglePaint ??= Angle.CreatePaint(); @@ -83,6 +83,9 @@ public struct Theme { public StylePaint FramePaint => _frame ??= Frame.CreatePaint(); public StylePaint CommentPaint => _comment ??= Comment.CreatePaint(); public SKPaint CommentBoxPaint => _commentBox ??= Comment.CreateForegroundPaint(SKPaintStyle.Stroke); + + public SKPaint StatusFgPaint => _statusFgPaint ??= new SKPaint { ColorF = StatusFg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; + public SKPaint SubpixelIndicatorDotPaint => _subpixelIndicatorDotPaint ??= new SKPaint { ColorF = SubpixelIndicatorDot.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; public SKPaint PopupMenuFgPaint => _popupMenuFgPaint ??= new SKPaint { ColorF = PopupMenuFg.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; public SKPaint PopupMenuFgDisabledPaint => _popupMenuFgDisabledPaint ??= new SKPaint { ColorF = PopupMenuFgDisabled.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; public SKPaint PopupMenuFgExtraPaint => _popupMenuFgExtraPaint ??= new SKPaint { ColorF = PopupMenuFgExtra.ToSkia(), Style = SKPaintStyle.Fill, IsAntialias = true }; @@ -99,6 +102,9 @@ public void InvalidateCache() { _frame?.Dispose(); _comment?.Dispose(); _commentBox?.Dispose(); + + _statusFgPaint?.Dispose(); + _subpixelIndicatorDotPaint?.Dispose(); _popupMenuFgPaint?.Dispose(); _popupMenuFgDisabledPaint?.Dispose(); _popupMenuFgExtraPaint?.Dispose(); @@ -106,7 +112,7 @@ public void InvalidateCache() { _popupMenuSelectedPaint?.Dispose(); _actionPaint = _anglePaint = _breakpointPaint = _savestateBreakpointPaint = _delimiter = _command = _frame = _comment = null; - _commentBox = _popupMenuFgPaint = _popupMenuFgDisabledPaint = _popupMenuFgExtraPaint = _popupMenuBgPaint = _popupMenuSelectedPaint = null; + _commentBox = _statusFgPaint = _subpixelIndicatorDotPaint = _popupMenuFgPaint = _popupMenuFgDisabledPaint = _popupMenuFgExtraPaint = _popupMenuBgPaint = _popupMenuSelectedPaint = null; } public bool DarkMode; diff --git a/Studio/CelesteStudio/FontManager.cs b/Studio/CelesteStudio/FontManager.cs index 24dfbec4..e7ce2931 100644 --- a/Studio/CelesteStudio/FontManager.cs +++ b/Studio/CelesteStudio/FontManager.cs @@ -18,7 +18,7 @@ public static class FontManager { #endif private static Font? editorFontRegular, editorFontBold, editorFontItalic, editorFontBoldItalic, statusFont; - private static SKFont? skEditorFontRegular, skEditorFontBold, skEditorFontItalic, skEditorFontBoldItalic, skPopupFont; + private static SKFont? skEditorFontRegular, skEditorFontBold, skEditorFontItalic, skEditorFontBoldItalic, skStatusFont, skPopupFont; public static Font EditorFontRegular => editorFontRegular ??= CreateEditor(FontStyle.None); public static Font EditorFontBold => editorFontBold ??= CreateEditor(FontStyle.Bold); @@ -30,6 +30,7 @@ public static class FontManager { public static SKFont SKEditorFontBold => skEditorFontBold ??= CreateSKFont(Settings.Instance.FontFamily, Settings.Instance.EditorFontSize * Settings.Instance.FontZoom, FontStyle.Bold); public static SKFont SKEditorFontItalic => skEditorFontItalic ??= CreateSKFont(Settings.Instance.FontFamily, Settings.Instance.EditorFontSize * Settings.Instance.FontZoom, FontStyle.Italic); public static SKFont SKEditorFontBoldItalic => skEditorFontBoldItalic ??= CreateSKFont(Settings.Instance.FontFamily, Settings.Instance.EditorFontSize * Settings.Instance.FontZoom, FontStyle.Bold | FontStyle.Italic); + public static SKFont SKStatusFont => skStatusFont ??= CreateSKFont(Settings.Instance.FontFamily, Settings.Instance.StatusFontSize); public static SKFont SKPopupFont => skPopupFont ??= CreateSKFont(Settings.Instance.FontFamily, Settings.Instance.PopupFontSize); private static FontFamily? builtinFontFamily; @@ -70,7 +71,7 @@ public static SKFont CreateSKFont(string fontFamily, float size, FontStyle style }); var typeface = SKTypeface.FromStream(stream); - return new SKFont(typeface, size * dpi) { LinearMetrics = true }; + return new SKFont(typeface, size * dpi) { LinearMetrics = true, Subpixel = true, Edging = SKFontEdging.SubpixelAntialias }; } else { var typeface = style switch { FontStyle.None => SKTypeface.FromFamilyName(fontFamily, SKFontStyleWeight.Light, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright), @@ -80,7 +81,7 @@ public static SKFont CreateSKFont(string fontFamily, float size, FontStyle style _ => throw new UnreachableException(), }; - return new SKFont(typeface, size * dpi) { LinearMetrics = true }; + return new SKFont(typeface, size * dpi) { LinearMetrics = true, Subpixel = true, Edging = SKFontEdging.SubpixelAntialias }; } } @@ -147,9 +148,10 @@ public static void OnFontChanged() { skEditorFontBold?.Dispose(); skEditorFontItalic?.Dispose(); skEditorFontBoldItalic?.Dispose(); + skStatusFont?.Dispose(); skPopupFont?.Dispose(); - skEditorFontRegular = skEditorFontBold = skEditorFontItalic = skEditorFontBoldItalic = skPopupFont = null; + skEditorFontRegular = skEditorFontBold = skEditorFontItalic = skEditorFontBoldItalic = skStatusFont = skPopupFont = null; } private static Font CreateEditor(FontStyle style) => CreateFont(Settings.Instance.FontFamily, Settings.Instance.EditorFontSize * Settings.Instance.FontZoom, style);