123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- using UnityEngine;
- using UnityEngine.Profiling;
- using System;
- // TODO: Find a way to break this the hell up.
- // TODO: Normalize conventions away from Java-style SetX to properties.
- public class SVGGraphicsFill : ISVGPathDraw {
- private const sbyte FILL_FLAG = -1;
- private readonly int[,] _neighbor = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
- private readonly SVGGraphics graphics;
- private readonly SVGBasicDraw basicDraw;
- private sbyte flagStep;
- private sbyte[,] flag;
- private int width, height;
- private int subW, subH;
- private int inZoneL, inZoneT;
- private Vector2 boundTopLeft, boundBottomRight;
- public SVGGraphicsFill(SVGGraphics _graphics) {
- graphics = _graphics;
- flagStep = 0;
- width = 0;
- height = 0;
- subW = subH = 0;
- //Basic Draw
- basicDraw = new SVGBasicDraw { SetPixelMethod = SetPixelForFlag };
- }
- public Vector2 Size {
- set {
- width = (int)value.x;
- height = (int)value.y;
- subW = width;
- subH = height;
- flag = new sbyte[(int)width + 1, (int)height + 1];
- }
- }
- public void SetColor(Color color) {
- graphics.SetColor(color);
- }
- private void SetPixelForFlag(int x, int y) {
- if(isInZone(x, y))
- flag[x, y] = flagStep;
- }
- private bool isInZone(int x, int y) {
- return ((x >= inZoneL && x < subW + inZoneL) && (y >= inZoneT && y < subH + inZoneT));
- }
- private void ExpandBounds(Vector2 point) {
- if(point.x < boundTopLeft.x)
- boundTopLeft.x = point.x;
- if(point.y < boundTopLeft.y)
- boundTopLeft.y = point.y;
- if(point.x > boundBottomRight.x)
- boundBottomRight.x = point.x;
- if(point.y > boundBottomRight.y)
- boundBottomRight.y = point.y;
- }
- private void ExpandBounds(Vector2 point, float dx, float dy) {
- if(point.x - dy < boundTopLeft.x)
- boundTopLeft.x = point.x - dx;
- if(point.y - dx < boundTopLeft.y)
- boundTopLeft.y = point.y - dy;
- if(point.x + dx > boundBottomRight.x)
- boundBottomRight.x = point.x + dx;
- if(point.y + dy > boundBottomRight.y)
- boundBottomRight.y = point.y + dy;
- }
- private void ExpandBounds(Vector2[] points) {
- int _length = points.Length;
- for(int i = 0; i < _length; i++)
- ExpandBounds(points[i]);
- }
- private static readonly LiteStack<IntVector2> _stack = new LiteStack<IntVector2>();
- private struct IntVector2 {
- public int x;
- public int y;
- }
- private void Fill(int x, int y) {
- // Debug.LogFormat("Fill called: w:{0}, h:{1}, subW:{2}, subH:{3}, inZoneL:{4}, inZoneT:{5}, x:{6}, y:{7}", width, height, subW, subH, inZoneL, inZoneT, x, y);
- Profiler.BeginSample("SVGGraphicsFill.Fill");
- if(!isInZone(x, y) || flag[x, y] != 0) {
- Profiler.EndSample();
- return;
- }
- flag[x, y] = FILL_FLAG;
- _stack.Clear();
- int anticipatedCapacityNeed = ((width + height) / 2) * 5;
- if(_stack.Capacity < anticipatedCapacityNeed)
- _stack.Capacity = anticipatedCapacityNeed;
- IntVector2 temp = new IntVector2 { x = x, y = y };
- _stack.Push(temp);
- int nbIterations = 0;
- while(_stack.Count > 0) {
- ++nbIterations;
- temp = _stack.Pop();
- for(int t = 0; t < 4; ++t) {
- int tx = temp.x + _neighbor[t, 0];
- int ty = temp.y + _neighbor[t, 1];
- if(isInZone(tx, ty) && flag[tx, ty] == 0) {
- flag[tx, ty] = FILL_FLAG;
- _stack.Push(new IntVector2 { x = tx, y = ty });
- }
- }
- }
- // Debug.LogFormat("NbIter:{0}", nbIterations);
- Profiler.EndSample();
- }
- public void ResetSubBuffer() {
- boundTopLeft = new Vector2(+10000f, +10000f);
- boundBottomRight = new Vector2(-10000f, -10000f);
- subW = width;
- subH = height;
- inZoneL = 0;
- inZoneT = 0;
- for(int i = 0; i < width; i++)
- for(int j = 0; j < height; j++)
- flag[i, j] = 0;
- flagStep = 1;
- }
- private void PreEndSubBuffer() {
- if(boundTopLeft.x < 0f)
- boundTopLeft.x = 0f;
- if(boundTopLeft.y < 0f)
- boundTopLeft.y = 0f;
- if(boundBottomRight.x >= width)
- boundBottomRight.x = width - 1f;
- if(boundBottomRight.y >= height)
- boundBottomRight.y = height - 1f;
- subW = Math.Abs((int)boundTopLeft.x - (int)boundBottomRight.x) + 3;
- subH = Math.Abs((int)boundTopLeft.y - (int)boundBottomRight.y) + 3;
- inZoneL = (int)boundTopLeft.x - 1;
- inZoneT = (int)boundTopLeft.y - 1;
- inZoneL = (inZoneL < 0) ? 0 : inZoneL;
- inZoneT = (inZoneT < 0) ? 0 : inZoneT;
- inZoneL = (inZoneL >= width) ? (width - 1) : inZoneL;
- inZoneT = (inZoneT >= height) ? (height - 1) : inZoneT;
- subW = (subW + inZoneL > width) ? (width - inZoneL) : subW;
- subH = (subH + inZoneT > height) ? (height - inZoneT) : subH;
- Fill(inZoneL, inZoneT);
- // TODO: This seems buggy:
- if((inZoneL == 0) && (inZoneT == 0))
- Fill(subW - 1, subH - 1);
- }
- private void FillInZone() {
- for(int i = inZoneL; i < subW + inZoneL; i++)
- for(int j = inZoneT; j < subH + inZoneT; j++)
- if(flag[i, j] != FILL_FLAG)
- graphics.SetPixel(i, j);
- }
- public void EndSubBuffer() {
- PreEndSubBuffer();
- Fill(inZoneL, inZoneT);
- FillInZone();
- }
- public void EndSubBuffer(Vector2[] points) {
- PreEndSubBuffer();
- for(int i = 0; i < points.GetLength(0); i++)
- Fill((int)points[i].x, (int)points[i].y);
- FillInZone();
- }
- public void EndSubBuffer(Vector2 point) {
- PreEndSubBuffer();
- Fill((int)point.x, (int)point.y);
- FillInZone();
- }
- public void EndSubBuffer(SVGColor? strokePathColor) {
- PreEndSubBuffer();
- FillInZone();
- graphics.SetColor(strokePathColor.Value.color);
- FillInZone();
- }
- public void EndSubBuffer(SVGLinearGradientBrush linearGradientBrush) {
- PreEndSubBuffer();
- for(int i = inZoneL; i < subW + inZoneL; i++) {
- for(int j = inZoneT; j < subH + inZoneT; j++) {
- if(flag[i, j] == 0) {
- Color _color = linearGradientBrush.GetColor(i, j);
- graphics.SetColor(_color);
- graphics.SetPixel(i, j);
- }
- }
- }
- }
- public void EndSubBuffer(SVGLinearGradientBrush linearGradientBrush, SVGColor? strokePathColor) {
- PreEndSubBuffer();
- for(int i = inZoneL; i < subW + inZoneL; i++) {
- for(int j = inZoneT; j < subH + inZoneT; j++) {
- if(flag[i, j] != FILL_FLAG) {
- Color _color = linearGradientBrush.GetColor(i, j);
- graphics.SetColor(_color);
- graphics.SetPixel(i, j);
- }
- }
- }
- graphics.SetColor(strokePathColor.Value.color);
- FillInZone();
- }
- public void EndSubBuffer(SVGRadialGradientBrush radialGradientBrush) {
- PreEndSubBuffer();
- for(int i = inZoneL; i < subW + inZoneL; i++) {
- for(int j = inZoneT; j < subH + inZoneT; j++) {
- if(flag[i, j] == 0) {
- Color _color = radialGradientBrush.GetColor(i, j);
- graphics.SetColor(_color);
- graphics.SetPixel(i, j);
- }
- }
- }
- }
- public void EndSubBuffer(SVGRadialGradientBrush radialGradientBrush, SVGColor? strokePathColor) {
- PreEndSubBuffer();
- for(int i = inZoneL; i < subW + inZoneL; ++i) {
- for(int j = inZoneT; j < subH + inZoneT; ++j) {
- if(flag[i, j] != FILL_FLAG) {
- Color _color = radialGradientBrush.GetColor(i, j);
- graphics.SetColor(_color);
- graphics.SetPixel(i, j);
- }
- }
- }
- graphics.SetColor(strokePathColor.Value.color);
- FillInZone();
- }
- private void PreRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4) {
- ResetSubBuffer();
- ExpandBounds(p1);
- ExpandBounds(p2);
- ExpandBounds(p3);
- ExpandBounds(p4);
- basicDraw.MoveTo(p1);
- basicDraw.LineTo(p2);
- basicDraw.LineTo(p3);
- basicDraw.LineTo(p4);
- basicDraw.LineTo(p1);
- }
- public void Rect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4) {
- PreRect(p1, p2, p3, p4);
- EndSubBuffer();
- }
- public void Rect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, SVGColor? strokeColor) {
- PreRect(p1, p2, p3, p4);
- EndSubBuffer(strokeColor);
- }
- public void Rect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, SVGColor fillColor, SVGColor? strokeColor) {
- SetColor(fillColor.color);
- PreRect(p1, p2, p3, p4);
- EndSubBuffer(strokeColor);
- }
- private void PreRoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7,
- Vector2 p8, float r1, float r2, float angle) {
- float dxy = ((r1 > r2) ? (int)r1 : (int)r2);
- ResetSubBuffer();
- ExpandBounds(p1, dxy, dxy);
- ExpandBounds(p2, dxy, dxy);
- ExpandBounds(p3, dxy, dxy);
- ExpandBounds(p4, dxy, dxy);
- ExpandBounds(p5, dxy, dxy);
- ExpandBounds(p6, dxy, dxy);
- ExpandBounds(p7, dxy, dxy);
- ExpandBounds(p8, dxy, dxy);
- basicDraw.MoveTo(p1);
- basicDraw.LineTo(p2);
- basicDraw.ArcTo(r1, r2, angle, false, true, p3);
- basicDraw.MoveTo(p3);
- basicDraw.LineTo(p4);
- basicDraw.ArcTo(r1, r2, angle, false, true, p5);
- basicDraw.MoveTo(p5);
- basicDraw.LineTo(p6);
- basicDraw.ArcTo(r1, r2, angle, false, true, p7);
- basicDraw.MoveTo(p7);
- basicDraw.LineTo(p8);
- basicDraw.ArcTo(r1, r2, angle, false, true, p1);
- }
- public void RoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7, Vector2 p8,
- float r1, float r2,
- float angle) {
- PreRoundedRect(p1, p2, p3, p4, p5, p6, p7, p8, r1, r2,
- angle);
- EndSubBuffer();
- }
- public void RoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7, Vector2 p8,
- float r1, float r2,
- float angle, SVGColor? strokeColor) {
- PreRoundedRect(p1, p2, p3, p4, p5, p6, p7, p8, r1, r2,
- angle);
- EndSubBuffer(strokeColor);
- }
- public void RoundedRect(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Vector2 p5, Vector2 p6, Vector2 p7, Vector2 p8,
- float r1, float r2,
- float angle, SVGColor fillColor, SVGColor? strokeColor) {
- SetColor(fillColor.color);
- PreRoundedRect(p1, p2, p3, p4, p5, p6, p7, p8, r1, r2,
- angle);
- EndSubBuffer(strokeColor);
- }
- private void PreCircle(Vector2 p, float r) {
- ResetSubBuffer();
- ExpandBounds(p, (int)r + 2, (int)r + 2);
- basicDraw.Circle(p, r);
- }
- public void Circle(Vector2 p, float r) {
- PreCircle(p, r);
- EndSubBuffer();
- }
- public void Circle(Vector2 p, float r, SVGColor? strokeColor) {
- PreCircle(p, r);
- EndSubBuffer(strokeColor);
- }
- public void Circle(Vector2 p, float r, SVGColor fillColor, SVGColor? strokeColor) {
- SetColor(fillColor.color);
- PreCircle(p, r);
- EndSubBuffer();
- }
- private void PreEllipse(Vector2 p, float rx, float ry, float angle) {
- int d = (rx > ry) ? (int)rx : (int)ry;
- ExpandBounds(p, d, d);
- basicDraw.Ellipse(p, (int)rx, (int)ry, angle);
- }
- public void Ellipse(Vector2 p, float rx, float ry, float angle) {
- PreEllipse(p, rx, ry, angle);
- EndSubBuffer();
- }
- public void Ellipse(Vector2 p, float rx, float ry, float angle, SVGColor? strokeColor) {
- PreEllipse(p, rx, ry, angle);
- EndSubBuffer(strokeColor);
- }
- public void Ellipse(Vector2 p, float rx, float ry, float angle, SVGColor fillColor, SVGColor? strokeColor) {
- SetColor(fillColor.color);
- PreEllipse(p, rx, ry, angle);
- EndSubBuffer(strokeColor);
- }
- private void PrePolygon(Vector2[] points) {
- if((points != null) && (points.GetLength(0) > 0)) {
- ResetSubBuffer();
- ExpandBounds(points);
- basicDraw.MoveTo(points[0]);
- int _length = points.GetLength(0);
- for(int i = 1; i < _length; i++)
- basicDraw.LineTo(points[i]);
- basicDraw.LineTo(points[0]);
- }
- }
- public void Polygon(Vector2[] points) {
- PrePolygon(points);
- EndSubBuffer();
- }
- public void Polygon(Vector2[] points, SVGColor? strokeColor) {
- PrePolygon(points);
- EndSubBuffer(strokeColor);
- }
- public void Polygon(Vector2[] points, SVGColor fillColor, SVGColor? strokeColor) {
- SetColor(fillColor.color);
- PrePolygon(points);
- EndSubBuffer(strokeColor);
- }
- public void FillPath(SVGGraphicsPath graphicsPath) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- EndSubBuffer();
- }
- public void FillPath(SVGGraphicsPath graphicsPath, Vector2[] points) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- EndSubBuffer(points);
- }
- public void FillPath(SVGGraphicsPath graphicsPath, Vector2 point) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- EndSubBuffer(point);
- }
- public void FillPath(SVGColor fillColor, SVGGraphicsPath graphicsPath) {
- SetColor(fillColor.color);
- FillPath(graphicsPath);
- }
- public void FillPath(SVGColor fillColor, SVGColor? strokePathColor, SVGGraphicsPath graphicsPath) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- if(strokePathColor != null)
- EndSubBuffer(strokePathColor);
- else
- EndSubBuffer();
- }
- public void FillPath(SVGLinearGradientBrush linearGradientBrush, SVGGraphicsPath graphicsPath) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- EndSubBuffer(linearGradientBrush);
- }
- public void FillPath(SVGLinearGradientBrush linearGradientBrush, SVGColor? strokePathColor,
- SVGGraphicsPath graphicsPath) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- if(strokePathColor != null)
- EndSubBuffer(linearGradientBrush, strokePathColor);
- else
- EndSubBuffer(linearGradientBrush);
- }
- public void FillPath(SVGRadialGradientBrush radialGradientBrush, SVGGraphicsPath graphicsPath) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- EndSubBuffer(radialGradientBrush);
- }
- public void FillPath(SVGRadialGradientBrush radialGradientBrush, SVGColor? strokePathColor,
- SVGGraphicsPath graphicsPath) {
- ResetSubBuffer();
- graphicsPath.RenderPath(this, true);
- if(strokePathColor != null)
- EndSubBuffer(radialGradientBrush, strokePathColor);
- else
- EndSubBuffer(radialGradientBrush);
- }
- public void CircleTo(Vector2 p, float r) {
- ExpandBounds(p, (int)r + 1, (int)r + 1);
- basicDraw.Circle(p, r);
- }
- public void EllipseTo(Vector2 p, float rx, float ry, float angle) {
- int d = (rx > ry) ? (int)rx + 2 : (int)ry + 2;
- ExpandBounds(p, d, d);
- basicDraw.Ellipse(p, (int)rx, (int)ry, angle);
- }
- public void LineTo(Vector2 p) {
- ExpandBounds(p);
- basicDraw.LineTo(p);
- }
- public void MoveTo(Vector2 p) {
- ExpandBounds(p);
- basicDraw.MoveTo(p);
- }
- public void ArcTo(float r1, float r2, float angle, bool largeArcFlag, bool sweepFlag, Vector2 p) {
- ExpandBounds(p, (r1 > r2) ? 2 * (int)r1 + 2 : 2 * (int)r2 + 2, (r1 > r2) ? 2 * (int)r1 + 2 : 2 * (int)r2 + 2);
- basicDraw.ArcTo(r1, r2, angle, largeArcFlag, sweepFlag, p);
- }
- public void CubicCurveTo(Vector2 p1, Vector2 p2, Vector2 p) {
- ExpandBounds(p1);
- ExpandBounds(p2);
- ExpandBounds(p);
- basicDraw.CubicCurveTo(p1, p2, p);
- }
- public void QuadraticCurveTo(Vector2 p1, Vector2 p) {
- ExpandBounds(p1);
- ExpandBounds(p);
- basicDraw.QuadraticCurveTo(p1, p);
- }
- }
|