using System.Collections; using System.Collections.Generic; using System.Linq; using SkiaSharp; using UnityEngine; using UnityEngine.UIElements; namespace BITKit.UX { public class SkiaPainter : VisualElement { public new class UxmlFactory : UxmlFactory { } public SkiaPainter() { RegisterCallback(OnGeometryChanged); RegisterCallback(OnMouseDown); RegisterCallback(OnMouseUp); RegisterCallback(OnMouseMove); } private bool _isPainting; private readonly List _points = new(); private SKImageInfo _info; private SKCanvas _canvas; private SKSurface _surface; private Rect _rect; private Optional _backgroundColor=new (); // private readonly SKPaint _linePaint = new() // { // Style = SKPaintStyle.Stroke, // Color = SKColors.Red, // StrokeWidth = 5, // }; private readonly SKPaint _linePaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = SKColors.Black, // 笔画颜色为黑色 StrokeCap = SKStrokeCap.Round, // 笔画末端采用圆形 StrokeJoin = SKStrokeJoin.Round, // 笔画连接处采用圆形 StrokeWidth = 8, // 笔画宽度 IsAntialias = true // 使用抗锯齿 }; public void ClearCanvas() { _points.Clear(); Rebuild(); } private void OnMouseMove(MouseMoveEvent evt) { if (_isPainting is false) return; var pos = evt.localMousePosition; pos.y = layout.height - pos.y; var last = _points.LastOrDefault(); if (_rect.Contains(pos) is false) { if (last == default) return; _points.Add(default); return; } var originalPos = pos; if (last != default) { //pos = Vector2.Lerp(last, pos, 0.1f); _points.Add(Vector2.Lerp(last, pos, 0.1f)); _points.Add(Vector2.Lerp(last, pos, 0.2f)); //_points.Add(Vector2.Lerp(last, pos, 1f)); } else { _points.Add(pos); } //_points.Add(pos); if (originalPos != pos) { //_points.Add(originalPos); } Rebuild(); } private void OnMouseUp(MouseUpEvent evt) { _isPainting = false; var last = _points.LastOrDefault(); if (last != default) _points.Add(default); } private void OnMouseDown(MouseDownEvent evt) { _isPainting = true; } private void OnGeometryChanged(GeometryChangedEvent evt) { if(float.IsNaN(layout.width) || layout.width < 16 || float.IsNaN(layout.height) || layout.height<16) return; _linePaint.Color = resolvedStyle.color.ToSKColor(); _surface?.Dispose(); _canvas?.Dispose(); _info = new SKImageInfo((int)layout.width, (int)layout.height); _info.AlphaType = SKAlphaType.Premul; _surface = SKSurface.Create(_info); _canvas = _surface.Canvas; _rect = new Rect(0, 0, layout.width, layout.height); Rebuild(); } private void Rebuild() { if (_canvas is null) return; _canvas.Clear(resolvedStyle.backgroundColor.ToSKColor()); DoubleBuffer buffer = new(); _linePaint.StrokeWidth = 4; foreach (var pos in _points) { if (pos == default) { buffer.Clear(); } else { if (buffer.TryGetRelease(out var previousPoint)) { _canvas.DrawLine(previousPoint.x, previousPoint.y, pos.x, pos.y, _linePaint); } buffer.Release(pos); } } var texture = _info.ToTexture2D(_surface); style.backgroundImage = texture; } public string Base64 => _surface?.GetBase64(); public byte[] Bytes => _surface?.GetBytes(); } }