using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net.Sockets.Kcp; 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 readonly SKPaint _linePaint = new() { Style = SKPaintStyle.Stroke, Color = SKColors.Red, StrokeWidth = 5 }; 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; if (_rect.Contains(pos) is false) { var last = _points.LastOrDefault(); if (last == default) return; _points.Add(default); return; } _points.Add(pos); 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) || float.IsNaN(layout.height)) return; _linePaint.Color = resolvedStyle.color.ToSKColor(); _surface?.Dispose(); _info = new SKImageInfo((int)layout.width, (int)layout.height); _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(); DoubleBuffer buffer = new(); 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(); } }