using System.Collections.Generic; using UnityEngine; using UnityEngine.Profiling; public enum SVGFillRule : ushort { NoneZero = 0, EvenOdd = 1 } // TODO: Find a way to break this the hell up. // TODO: Normalize conventions away from Java-style SetX to properties. public class SVGGraphicsPath { private Vector2 beginPoint; private Vector2 boundUL, boundBR; private bool needSetFirstPoint; private Matrix2x3 _matrixTransform; private readonly List listObject = new List(); public SVGFillRule fillRule = SVGFillRule.NoneZero; public Matrix2x3 matrixTransform { get { if(_matrixTransform == null) _matrixTransform = transformList.Consolidate().matrix; return _matrixTransform; } } public float transformAngle { get { float angle = 0.0f; for(int i = 0; i < transformList.Count; ++i) { SVGTransform temp = transformList[i]; if(temp.type == SVGTransformMode.Rotate) angle += temp.angle; } return angle; } } public SVGTransformList transformList { get; set; } public SVGGraphicsPath() { beginPoint = new Vector2(0f, 0f); needSetFirstPoint = true; boundUL = new Vector2(+10000f, +10000f); boundBR = new Vector2(-10000f, -10000f); transformList = new SVGTransformList(); } public void Reset() { beginPoint = new Vector2(0f, 0f); needSetFirstPoint = true; boundUL = new Vector2(+10000f, +10000f); boundBR = new Vector2(-10000f, -10000f); fillRule = SVGFillRule.NoneZero; transformList.Clear(); listObject.Clear(); } public void ExpandBounds(float x, float y) { if(x < boundUL.x) boundUL.x = x; if(y < boundUL.y) boundUL.y = y; if(x > boundBR.x) boundBR.x = x; if(y > boundBR.y) boundBR.y = y; } private void ExpandBounds(float x, float y, float dx, float dy) { if((x - dx) < boundUL.x) boundUL.x = x - dx; if((y - dy) < boundUL.y) boundUL.y = y - dy; if((x + dx) > boundBR.x) boundBR.x = x + dx; if((y + dy) > boundBR.y) boundBR.y = y + dy; } public void ExpandBounds(Vector2 point) { ExpandBounds(point.x, point.y); } public void ExpandBounds(Vector2 point, float deltax, float deltay) { ExpandBounds(point.x, point.y, deltax, deltay); } public void ExpandBounds(List points) { int length = points.Count; for(int i = 0; i < length; i++) ExpandBounds(points[i]); } private void SetFirstPoint(Vector2 p) { if(needSetFirstPoint) { beginPoint = p; needSetFirstPoint = false; } } public void Add(SVGPolygonElement polygonElement) { SetFirstPoint(polygonElement.listPoints[0]); listObject.Add(new SVGGPolygon(polygonElement.listPoints)); } public void Add(SVGPolylineElement polylineElement) { SetFirstPoint(polylineElement.listPoints[0]); listObject.Add(new SVGGPolyLine(polylineElement.listPoints)); } public void Add(SVGRectElement rectElement) { SVGGRect rect = new SVGGRect(rectElement.x.value, rectElement.y.value, rectElement.width.value, rectElement.height.value, rectElement.rx.value, rectElement.ry.value); SetFirstPoint(new Vector2(rect.x, rect.y)); listObject.Add(rect); } public void Add(SVGCircleElement circleElement) { Vector2 p = new Vector2(circleElement.cx.value, circleElement.cy.value); SetFirstPoint(p); listObject.Add(new SVGGCircle(p, circleElement.r.value)); } public void Add(SVGEllipseElement ellipseElement) { Vector2 p = new Vector2(ellipseElement.cx.value, ellipseElement.cy.value); SetFirstPoint(p); listObject.Add(new SVGGEllipse(p, ellipseElement.rx.value, ellipseElement.ry.value, 0)); } public void AddCircleTo(Vector2 p, float r) { listObject.Add(new SVGGCircle(p, r)); } public void AddEllipseTo(Vector2 p, float r1, float r2, float angle) { listObject.Add(new SVGGEllipse(p, r1, r2, angle)); } public void AddMoveTo(Vector2 p) { SetFirstPoint(p); listObject.Add(new SVGGMoveTo(p)); } public void AddArcTo(float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, Vector2 p) { SVGGArcAbs svgGArcAbs = new SVGGArcAbs(r1, r2, angle, largeArcFlag, sweepFlag, p); listObject.Add(svgGArcAbs); } public void AddCubicCurveTo(Vector2 p1, Vector2 p2, Vector2 p) { SVGGCubicAbs svgGCubicAbs = new SVGGCubicAbs(p1, p2, p); listObject.Add(svgGCubicAbs); } public void AddQuadraticCurveTo(Vector2 p1, Vector2 p) { SVGGQuadraticAbs svgGQuadraticAbs = new SVGGQuadraticAbs(p1, p); listObject.Add(svgGQuadraticAbs); } public void AddLineTo(Vector2 p) { listObject.Add(new SVGGLineTo(p)); } public Rect GetBound() { Profiler.BeginSample("SVGGraphicsPath.GetBound"); for(int i = 0; i < listObject.Count; ++i) { ISVGPathSegment seg = listObject[i]; seg.ExpandBounds(this); } Rect tmp = new Rect(boundUL.x - 1, boundUL.y - 1, boundBR.x - boundUL.x + 2, boundBR.y - boundUL.y + 2); Profiler.EndSample(); return tmp; } public void RenderPath(ISVGPathDraw pathDraw, bool isClose) { Profiler.BeginSample("SVGGraphicsPath.RenderPath"); isClose = !isClose; Profiler.BeginSample("SVGGraphicsPath.RenderPath[for...]"); for(int i = 0; i < listObject.Count; i++) { Profiler.BeginSample("SVGGraphicsPath.RenderPath[...each]"); ISVGPathSegment seg = listObject[i]; isClose = seg.Render(this, pathDraw) || isClose; Profiler.EndSample(); } Profiler.EndSample(); if(!isClose) { Profiler.BeginSample("SVGPathSegment.Render[LineTo]"); pathDraw.LineTo(matrixTransform.Transform(beginPoint)); Profiler.EndSample(); } Profiler.EndSample(); } }