Ledger Nano X - The secure hardware wallet
SHARE
TWEET

Lines.cs

mvaganov Jul 15th, 2014 (edited) 576 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3.  
  4. // author: mvaganov@hotmail.com
  5. // license: Copyfree, public domain. This is free code! Great artists, steal this code!
  6. // latest version at: https://pastebin.com/raw/8m69iTut -- last updated (2020/03/17)
  7. namespace NS
  8. {
  9.     /// <summary>static functions for Unity's LineRenderer. Creates visualizations for 3D Vector math.
  10.     /// This library isn't optimized for performance, it's built to make math less invisible, even at compiled runtime.
  11.     /// </summary>
  12.     public class Lines : MonoBehaviour
  13.     {
  14.         [Tooltip("Used to draw lines. Ideally a white Sprites/Default shader.")]
  15.         public Material lineMaterial;
  16.         public bool autoParentLinesToGlobalObject = true;
  17.  
  18.         /// <summary>the dictionary of named lines. This structure allows Lines to create new lines without needing explicit variables</summary>
  19.         static Dictionary<string, GameObject> namedObject = new Dictionary<string, GameObject>();
  20.         /// <summary>The singleton instance.</summary>
  21.         static Lines instance;
  22.  
  23.         public static Lines Instance()
  24.         {
  25.             if (instance == null)
  26.             {
  27.                 instance = FindComponentInstance<Lines>();
  28.             }
  29.             return instance;
  30.         }
  31.         public static T FindComponentInstance<T>() where T : Component
  32.         {
  33.             T instance = null;
  34.             if ((instance = FindObjectOfType(typeof(T)) as T) == null)
  35.             {
  36.                 GameObject g = new GameObject("<" + typeof(T).Name + ">");
  37.                 instance = g.AddComponent<T>();
  38.             }
  39.             return instance;
  40.         }
  41.  
  42.         void Start()
  43.         {
  44.             if (instance != null && instance != this)
  45.             {
  46.                 Debug.LogWarning("<Lines> should be a singleton. Deleting extra");
  47.                 Destroy(this);
  48.             }
  49.         }
  50.  
  51.         /// <param name="name"></param>
  52.         /// <param name="createIfNotFound">if true, this function will not return null</param>
  53.         /// <returns>a line object with the given name. can return null if no such object has been made yet with this function</returns>
  54.         public static GameObject Get(string name, bool createIfNotFound = false)
  55.         {
  56.             GameObject go;
  57.             if ((!namedObject.TryGetValue(name, out go) || go == null) && createIfNotFound)
  58.             {
  59.                 go = namedObject[name] = MakeLineRenderer(ref go).gameObject;
  60.                 go.name = name;
  61.             }
  62.             return go;
  63.         }
  64.  
  65.         public static Line_ Make(string name, bool createIfNotFound = true)
  66.         {
  67.             Line_ line_ = null;
  68.             GameObject go = Get(name, createIfNotFound);
  69.             if (go != null)
  70.             {
  71.                 line_ = go.GetComponent<Line_>();
  72.                 if (line_ == null) { line_ = go.AddComponent<Line_>(); }
  73.             }
  74.             return line_;
  75.         }
  76.         public enum End { normal, arrow, arrowBothEnds };
  77.         /// <summary>cached calculations. used to validate if a line needs to be re-calculated</summary>
  78.         public class Line_ : MonoBehaviour
  79.         {
  80.             public enum Kind { none, line, arc, orbital, spiralSphere, box, quaternion, disabled }
  81.             Kind _kind;
  82.             Vector3[] points;
  83.             Vector3 normal;
  84.             Quaternion rotation;
  85.             int count;
  86.             float startSize, endSize, angle;
  87.             End lineEnds;
  88.             LineRenderer lr;
  89.             public int numCapVertices { get { return lr.numCapVertices; } set { lr.numCapVertices = value; } }
  90.  
  91.             public Kind kind {
  92.                 get { return _kind; }
  93.                 set {
  94.                     if (_kind == Kind.quaternion && value != Kind.quaternion)
  95.                     {
  96.                         GameObject[] obj = QuaternionAngleChildObjects(points.Length, false);
  97.                         if (obj != null)
  98.                         {
  99.                             System.Array.ForEach(obj, o => { o.transform.SetParent(null); Destroy(o); });
  100.                         }
  101.                     }
  102.                     _kind = value;
  103.                 }
  104.             }
  105.  
  106.             private static bool SameArrayOfVectors(Vector3[] a, Vector3[] b)
  107.             {
  108.                 if (ReferenceEquals(a, b)) { return true; }
  109.                 if (a == null || b == null || a.Length != b.Length) { return false; }
  110.                 for (int i = 0; i < a.Length; ++i) { if (a[i] != b[i]) return false; }
  111.                 return true;
  112.             }
  113.             private bool IsLine(Vector3[] points, float startSize, float endSize, End lineEnds)
  114.             {
  115.                 return kind == Kind.line && SameArrayOfVectors(this.points, points)
  116.                     && startSize == this.startSize && endSize == this.endSize && this.lineEnds == lineEnds;
  117.             }
  118.             private void SetLine(Vector3[] points, float startSize, float endSize, End lineEnds)
  119.             {
  120.                 kind = Kind.line;
  121.                 this.points = new Vector3[points.Length]; System.Array.Copy(points, this.points, points.Length);
  122.                 this.startSize = startSize; this.endSize = endSize; this.lineEnds = lineEnds;
  123.             }
  124.             private bool IsArc(Vector3 start, Vector3 normal, Vector3 center, float angle, float startSize, float endSize, End lineEnds, int pointCount)
  125.             {
  126.                 return kind == Kind.arc && points != null && points.Length == 1 && points[0] == start && count == pointCount
  127.                     && this.normal == normal && startSize == this.startSize && endSize == this.endSize && this.lineEnds == lineEnds
  128.                     && this.transform.position == center && this.normal == normal && this.angle == angle;
  129.             }
  130.             private void SetArc(Vector3 start, Vector3 normal, Vector3 center, float angle, float startSize, float endSize, End lineEnds, int pointCount)
  131.             {
  132.                 kind = Kind.arc;
  133.                 points = new Vector3[] { start }; count = pointCount;
  134.                 this.startSize = startSize; this.endSize = endSize; this.lineEnds = lineEnds;
  135.                 this.transform.position = center; this.normal = normal; this.angle = angle;
  136.             }
  137.             private bool IsOrbital(Vector3 start, Vector3 end, Vector3 center, float startSize, float endSize, End lineEnds, int pointCount)
  138.             {
  139.                 return kind == Kind.orbital && points != null && points.Length == 2 && count == pointCount
  140.                     && points[0] == start && points[1] == end
  141.                     && startSize == this.startSize && endSize == this.endSize && this.lineEnds == lineEnds
  142.                     && this.transform.position == center;
  143.             }
  144.             private void SetOrbital(Vector3 start, Vector3 end, Vector3 center = default, float startSize = LINESIZE, float endSize = LINESIZE,
  145.                 End lineEnds = default, int pointCount = -1)
  146.             {
  147.                 kind = Kind.orbital;
  148.                 points = new Vector3[] { start, end }; count = pointCount;
  149.                 this.startSize = startSize; this.endSize = endSize; this.lineEnds = lineEnds;
  150.                 this.transform.position = center;
  151.             }
  152.             private bool IsSpiralSphere(Vector3 center, float radius, float linesize, Quaternion rotation)
  153.             {
  154.                 return kind == Kind.spiralSphere
  155.                     && this.startSize == linesize && this.endSize == linesize
  156.                     && this.transform.position == center && this.angle == radius
  157.                     && (this.rotation.Equals(rotation) || this.rotation == rotation);
  158.             }
  159.             private void SetSpiralSphere(Vector3 center, float radius, float linesize, Quaternion rotation)
  160.             {
  161.                 kind = Kind.spiralSphere;
  162.                 startSize = endSize = linesize;
  163.                 this.transform.position = center; angle = radius; this.rotation = rotation;
  164.             }
  165.             private bool IsBox(Vector3 center, Vector3 size, Quaternion rotation, float linesize)
  166.             {
  167.                 return kind == Kind.box
  168.                     && this.startSize == linesize && this.endSize == linesize
  169.                     && this.transform.position == center
  170.                     && transform.localScale == size && transform.rotation == rotation;
  171.             }
  172.             private void SetBox(Vector3 center, Vector3 size, Quaternion rotation, float linesize)
  173.             {
  174.                 kind = Kind.box;
  175.                 startSize = endSize = linesize;
  176.                 this.transform.position = center;
  177.                 transform.localScale = size; transform.rotation = rotation;
  178.             }
  179.             private bool IsQuaternion(float an, Vector3 ax, Vector3 position, Vector3[] startPoints, Quaternion orientation, int arcPoints, float linesize)
  180.             {
  181.                 return kind == Kind.quaternion && SameArrayOfVectors(this.points, startPoints)
  182.                     && this.startSize == linesize && this.endSize == linesize
  183.                     && this.transform.position == position && normal == ax && angle == an && count == arcPoints
  184.                     && (rotation.Equals(orientation) || rotation == orientation); // quaternions can't easily be tested for equality because of floating point errors
  185.             }
  186.             private void SetQuaternion(float an, Vector3 ax, Vector3 position, Vector3[] startPoints, Quaternion orientation, int arcPoints, float linesize)
  187.             {
  188.                 kind = Kind.quaternion;
  189.                 if (ReferenceEquals(startPoints, default_quaternion_visualization_points))
  190.                 {
  191.                     points = default_quaternion_visualization_points;
  192.                 } else
  193.                 {
  194.                     points = new Vector3[startPoints.Length]; System.Array.Copy(startPoints, points, startPoints.Length);
  195.                 }
  196.                 startSize = endSize = linesize;
  197.                 this.transform.position = position; normal = ax; angle = an; count = arcPoints;
  198.                 rotation = orientation;
  199.             }
  200.             private static LineRenderer MakeLine(ref GameObject go, Vector3[] points, Color color, float startSize, float endSize, End lineEnds)
  201.             {
  202.                 LineRenderer lr;
  203.                 if (lineEnds == End.arrow || lineEnds == End.arrowBothEnds)
  204.                 {
  205.                     Vector3[] line;
  206.                     Keyframe[] keyframes = CalculateArrowKeyframes(points, points.Length, out line, startSize, endSize, ARROWSIZE, null);
  207.                     lr = MakeArrow(ref go, line, line.Length, color, startSize, endSize);
  208.                     lr.widthCurve = new AnimationCurve(keyframes);
  209.                     if (lineEnds == End.arrowBothEnds)
  210.                     {
  211.                         ReverseLineInternal(ref lr);
  212.                         Vector3[] p = new Vector3[lr.positionCount];
  213.                         lr.GetPositions(p);
  214.                         lr = MakeArrow(ref go, p, p.Length, color, endSize, startSize, ARROWSIZE, lr.widthCurve.keys);
  215.                         ReverseLineInternal(ref lr);
  216.                     }
  217.                 } else
  218.                 {
  219.                     lr = Make(ref go, points, points.Length, color, startSize, endSize);
  220.                 }
  221.                 return lr;
  222.             }
  223.  
  224.             public Line_ Line(Vector3 start, Vector3 end, Color color = default, float startSize = LINESIZE, float endSize = LINESIZE)
  225.             {
  226.                 return Line(new Vector3[] { start, end }, color, End.normal, startSize, endSize);
  227.             }
  228.             public Line_ Arrow(Vector3 vector, Color color = default, float startSize = LINESIZE, float endSize = LINESIZE)
  229.             {
  230.                 return Line(new Vector3[] { Vector3.zero, vector }, color, End.arrow, startSize, endSize);
  231.             }
  232.             public Line_ Arrow(Vector3 start, Vector3 end, Color color = default, float startSize = LINESIZE, float endSize = LINESIZE)
  233.             {
  234.                 return Line(new Vector3[] { start, end }, color, End.arrow, startSize, endSize);
  235.             }
  236.             public Line_ Line(Vector3[] points, Color color = default, End lineEnds = default, float startSize = LINESIZE, float endSize = LINESIZE)
  237.             {
  238.                 GameObject go = gameObject;
  239.                 if (!IsLine(points, startSize, endSize, lineEnds))
  240.                 {
  241.                     SetLine(points, startSize, endSize, lineEnds);
  242.                     lr = MakeLine(ref go, points, color, startSize, endSize, lineEnds);
  243.                 } //else { Debug.Log("don't need to recalculate line "+name); }
  244.                 SetColor(lr, color);
  245.                 return this;
  246.             }
  247.             public Line_ Arc(float angle, Vector3 normal, Vector3 firstPoint, Vector3 center = default(Vector3), Color color = default(Color),
  248.                 End lineEnds = default, int pointCount = -1, float startSize = LINESIZE, float endSize = LINESIZE)
  249.             {
  250.                 GameObject go = gameObject;
  251.                 if (pointCount < 0) { pointCount = (int)(24 * angle / 180f) + 1; }
  252.                 if (!IsArc(firstPoint, normal, center, angle, startSize, endSize, End.normal, pointCount))
  253.                 {
  254.                     SetArc(firstPoint, normal, center, angle, startSize, endSize, End.normal, pointCount);
  255.                     Vector3[] linepoints = null;
  256.                     WriteArc(ref linepoints, pointCount, normal, firstPoint, angle, center);
  257.                     lr = MakeLine(ref go, linepoints, color, startSize, endSize, lineEnds);
  258.                 } //else { Debug.Log("don't need to recalculate arc "+name);  }
  259.                 SetColor(lr, color);
  260.                 return this;
  261.             }
  262.             public Line_ Circle(Vector3 center = default, Vector3 normal = default, Color color = default, float radius = 1,
  263.                 int pointCount = -1, float linesize = LINESIZE)
  264.             {
  265.                 if (normal == default) { normal = Vector3.up; }
  266.                 Vector3 firstPoint = Vector3.zero;
  267.                 if (kind == Kind.arc && this.normal == normal && points != null && points.Length > 0)
  268.                 {
  269.                     float firstRad = points[0].magnitude;
  270.                     if (firstRad == radius)
  271.                     {
  272.                         firstPoint = points[0];
  273.                     } else
  274.                     {
  275.                         firstPoint = points[0] * (radius / firstRad);
  276.                     }
  277.                 }
  278.                 if (firstPoint == Vector3.zero)
  279.                 {
  280.                     firstPoint = Vector3.right;
  281.                     if (normal != Vector3.up && normal != Vector3.forward && normal != Vector3.back)
  282.                     {
  283.                         firstPoint = Vector3.Cross(normal, Vector3.forward).normalized;
  284.                     }
  285.                     firstPoint *= radius;
  286.                 }
  287.                 return Arc(360, normal, firstPoint, center, color, End.normal, pointCount, linesize);
  288.             }
  289.             public Line_ Orbital(Vector3 sphereCenter, Vector3 start, Vector3 end,
  290.                 Color color = default(Color), End lineEnds = default, float startSize = LINESIZE, float endSize = LINESIZE, int pointCount = -1)
  291.             {
  292.                 GameObject go = gameObject;
  293.                 if (!IsOrbital(start, end, sphereCenter, startSize, endSize, lineEnds, pointCount))
  294.                 {
  295.                     SetOrbital(start, end, sphereCenter, startSize, endSize, lineEnds, pointCount);
  296.                     Vector3[] linepoints = null;
  297.                     WriteArcOnSphere(ref linepoints, pointCount, sphereCenter, start, end);
  298.                     lr = MakeLine(ref go, linepoints, color, startSize, endSize, lineEnds);
  299.                 } //else { Debug.Log("don't need to recalculate orbital " + name); }
  300.                 SetColor(lr, color);
  301.                 return this;
  302.             }
  303.             public Line_ SpiralSphere(Color color = default, Vector3 center = default, float radius = 1, Quaternion rotation = default, float linesize = LINESIZE)
  304.             {
  305.                 GameObject go = gameObject;
  306.                 if (!IsSpiralSphere(center, radius, linesize, rotation))
  307.                 {
  308.                     SetSpiralSphere(center, radius, linesize, rotation);
  309.                     lr = MakeSpiralSphere(ref go, radius, center, rotation, color, linesize);
  310.                 } //else { Debug.Log("don't need to recalculate spiralsphere " + name); }
  311.                 SetColor(lr, color);
  312.                 return this;
  313.             }
  314.             public Line_ Box(Vector3 size, Vector3 center = default, Quaternion rotation = default, Color color = default, float linesize = LINESIZE)
  315.             {
  316.                 GameObject go = gameObject;
  317.                 if (!IsBox(center, size, rotation, linesize))
  318.                 {
  319.                     SetBox(center, size, rotation, linesize);
  320.                     lr = MakeBox(ref go, center, size, rotation, color, linesize);
  321.                 } //else { Debug.Log("don't need to recalculate box " + name); }
  322.                 SetColor(lr, color);
  323.                 return this;
  324.             }
  325.             private GameObject[] QuaternionAngleChildObjects(int objectCount, bool createIfNoneExist)
  326.             {
  327.                 GameObject[] angleObjs = null;
  328.                 const string _A = "_A";
  329.                 if (transform.childCount == objectCount)
  330.                 {
  331.                     int childrenWithLineRenderers = 0;
  332.                     Transform[] children = new Transform[transform.childCount];
  333.                     for (int i = 0; i < children.Length; ++i) { children[i] = transform.GetChild(i); }
  334.                     System.Array.ForEach(children, (child) => {
  335.                         if (child.name.Contains(_A) && child.GetComponent<LineRenderer>() != null) { ++childrenWithLineRenderers; }
  336.                     });
  337.                     if (childrenWithLineRenderers >= objectCount)
  338.                     {
  339.                         angleObjs = new GameObject[objectCount];
  340.                         int validLine = 0;
  341.                         for (int i = 0; i < children.Length && validLine < angleObjs.Length; ++i)
  342.                         {
  343.                             if (children[i].name.Contains(_A) && children[i].GetComponent<LineRenderer>() != null)
  344.                                 angleObjs[validLine++] = children[i].gameObject;
  345.                         }
  346.                     }
  347.                 }
  348.                 if (angleObjs == null && createIfNoneExist)
  349.                 {
  350.                     angleObjs = new GameObject[objectCount];
  351.                     for (int i = 0; i < angleObjs.Length; ++i)
  352.                     {
  353.                         GameObject angleObject = new GameObject(name + _A + i);
  354.                         angleObject.transform.SetParent(transform);
  355.                         angleObjs[i] = angleObject;
  356.                     }
  357.                 }
  358.                 return angleObjs;
  359.             }
  360.             private static Vector3[] default_quaternion_visualization_points = new Vector3[] { Vector3.forward, Vector3.up };
  361.             public Line_ Quaternion(Quaternion q, Color color, Vector3 position = default, Vector3[] startPoints = null,
  362.                 Quaternion orientation = default, int arcPoints = -1, float linesize = LINESIZE)
  363.             {
  364.                 GameObject go = gameObject;
  365.                 float an; Vector3 ax;
  366.                 q.ToAngleAxis(out an, out ax);
  367.                 if (startPoints == null) { startPoints = default_quaternion_visualization_points; }
  368.                 if (!IsQuaternion(an, ax, position, startPoints, orientation, arcPoints, linesize))
  369.                 {
  370.                     SetQuaternion(an, ax, position, startPoints, orientation, arcPoints, linesize);
  371.                     GameObject[] angleObjs = QuaternionAngleChildObjects(startPoints.Length, true);
  372.                     MakeQuaternion(ref go, angleObjs, ax, an, position, color, orientation, arcPoints, linesize, ARROWSIZE, startPoints);
  373.                     lr = go.GetComponent<LineRenderer>();
  374.                 } //else { Debug.Log("don't need to recalculate quaternion " + name); }
  375.                 SetColor(lr, color);
  376.                 return this;
  377.             }
  378.         }
  379.  
  380.         /// <summary>
  381.         /// Make the specified Line.
  382.         /// example usage:
  383.         /// <para><code>
  384.         /// /* GameObject forwardLine should be a member variable */
  385.         /// Lines.Make (ref forwardLine, transform.position,
  386.         ///             transform.position + transform.forward, Color.blue, 0.1f, 0);
  387.         /// //This makes a long thin triangle, pointing forward.
  388.         /// </code></para>
  389.         /// </summary>
  390.         /// <param name="lineObject">GameObject host of the LineRenderer</param>
  391.         /// <param name="start">Start, an absolute world-space coordinate</param>
  392.         /// <param name="end">End, an absolute world-space coordinate</param>
  393.         /// <param name="startSize">How wide the line is at the start</param>
  394.         /// <param name="endSize">How wide the line is at the end</param>
  395.         public static LineRenderer Make(ref GameObject lineObject, Vector3 start, Vector3 end,
  396.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)
  397.         {
  398.             LineRenderer lr = MakeLineRenderer(ref lineObject, color, startSize, endSize);
  399.             lr.positionCount = 2;
  400.             lr.SetPosition(0, start); lr.SetPosition(1, end);
  401.             return lr;
  402.         }
  403.  
  404.         /// <summary>convenience method</summary>
  405.         [System.Obsolete("use Lines.Make(name).Line instead, it's more performant.")]
  406.         public static LineRenderer Make(string lineName, Vector3 start, Vector3 end,
  407.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)
  408.         {
  409.             GameObject go = Get(lineName, true);
  410.             return Make(ref go, start, end, color, startSize, endSize);
  411.         }
  412.  
  413.         /// <summary>Make the specified Line from a list of points</summary>
  414.         /// <returns>The LineRenderer hosting the line</returns>
  415.         /// <param name="lineObject">GameObject host of the LineRenderer</param>
  416.         /// <param name="color">Color of the line</param>
  417.         /// <param name="points">List of absolute world-space coordinates</param>
  418.         /// <param name="pointCount">Number of the points used points list</param>
  419.         /// <param name="startSize">How wide the line is at the start</param>
  420.         /// <param name="endSize">How wide the line is at the end</param>
  421.         public static LineRenderer Make(ref GameObject lineObject, IList<Vector3> points, int pointCount,
  422.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)
  423.         {
  424.             LineRenderer lr = MakeLineRenderer(ref lineObject, color, startSize, endSize);
  425.             lr.positionCount = pointCount;
  426.             for (int i = 0; i < pointCount; ++i) { lr.SetPosition(i, points[i]); }
  427.             return lr;
  428.         }
  429.         /// <summary>convenience version of LineRenderer Make(ref GameObject lineObject, IList<Vector3> points, int pointCount,
  430.         /// Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)</summary>
  431.         [System.Obsolete("use Lines.Make(name).Line instead, it's more performant.")]
  432.         public static LineRenderer Make(string lineName, IList<Vector3> points,
  433.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)
  434.         {
  435.             GameObject go = Get(lineName, true);
  436.             return Make(ref go, points, points.Count, color, startSize, endSize);
  437.         }
  438.  
  439.         public static LineRenderer MakeLineRenderer(ref GameObject lineObject)
  440.         {
  441.             if (lineObject == null)
  442.             {
  443.                 lineObject = new GameObject();
  444.                 if (Instance().autoParentLinesToGlobalObject)
  445.                 {
  446.                     lineObject.transform.SetParent(instance.transform);
  447.                 }
  448.             }
  449.             LineRenderer lr = lineObject.GetComponent<LineRenderer>();
  450.             if (lr == null) { lr = lineObject.AddComponent<LineRenderer>(); }
  451.             return lr;
  452.         }
  453.  
  454.         public static LineRenderer MakeLineRenderer(ref GameObject lineObject, Color color, float startSize, float endSize)
  455.         {
  456.             LineRenderer lr = MakeLineRenderer(ref lineObject);
  457.             lr.startWidth = startSize;
  458.             lr.endWidth = endSize;
  459.             SetColor(lr, color);
  460.             return lr;
  461.         }
  462.  
  463.         public static Material FindShaderMaterial(string shadername)
  464.         {
  465.             Shader s = Shader.Find(shadername);
  466.             if (s == null)
  467.             {
  468.                 throw new System.Exception("Missing shader: " + shadername
  469.                     + ". Please make sure it is in the \"Resources\" folder, "
  470.                     + "or used by at least one other object. Or, create an "
  471.                     + " object with Lines, and assign the material manually");
  472.             }
  473.             return new Material(s);
  474.         }
  475.  
  476.         public static void SetColor(LineRenderer lr, Color color)
  477.         {
  478.             Material mat = Instance().lineMaterial;
  479.             if (mat == null)
  480.             {
  481.                 const string colorShaderName = "Sprites/Default";//"Unlit/Color";
  482.                 mat = FindShaderMaterial(colorShaderName);
  483.                 Instance().lineMaterial = mat;
  484.             }
  485.             if (lr.material == null || lr.material.name != mat.name) { lr.material = mat; }
  486.             if (color == default(Color)) { color = Color.magenta; } else
  487.             {
  488.                 float h, s, v;
  489.                 long t = System.DateTime.Now.Ticks / System.TimeSpan.TicksPerMillisecond;
  490.                 long duration = 500;
  491.                 long secComponent = t % duration;
  492.                 float a = Mathf.Abs((2f * secComponent - duration) / duration);
  493.                 Color.RGBToHSV(color, out h, out s, out v);
  494.                 color = Color.HSVToRGB(h, s + (a * .25f), v + (a * .25f));
  495.             }
  496.             lr.material.color = color;
  497.         }
  498.  
  499.         /// <summary>Write 2D arc in 3D space, into given Vector3 array</summary>
  500.         /// <param name="points">Will host the list of coordinates</param>
  501.         /// <param name="pointCount">How many vertices to make &gt; 1</param>
  502.         /// <param name="normal">The surface-normal of the arc's plane</param>
  503.         /// <param name="firstPoint">Arc start, rotate about Vector3.zero</param>
  504.         /// <param name="angle">2D angle. Tip: Vector3.Angle(v1, v2)</param>
  505.         /// <param name="offset">How to translate the arc</param>
  506.         public static void WriteArc(ref Vector3[] points, int pointCount,
  507.             Vector3 normal, Vector3 firstPoint, float angle = 360, Vector3 offset = default(Vector3), int startIndex = 0)
  508.         {
  509.             if (pointCount < 0)
  510.             {
  511.                 pointCount = (int)Mathf.Abs(24 * angle / 180f) + 1;
  512.             }
  513.             if (pointCount < 0 || pointCount >= 32767) { Debug.LogError("bad point count value: " + pointCount); }
  514.             if (points == null) { points = new Vector3[pointCount]; }
  515.             if (startIndex >= points.Length) return;
  516.             points[startIndex] = firstPoint;
  517.             Quaternion q = Quaternion.AngleAxis(angle / (pointCount - 1), normal);
  518.             for (int i = startIndex + 1; i < startIndex + pointCount; ++i) { points[i] = q * points[i - 1]; }
  519.             if (offset != Vector3.zero)
  520.                 for (int i = startIndex; i < startIndex + pointCount; ++i) { points[i] += offset; }
  521.         }
  522.  
  523.         [System.Obsolete("use Lines.Make(name).Arc instead, it's more performant.")]
  524.         public static LineRenderer MakeArc(string name,
  525.             float angle, int pointCount, Vector3 normal, Vector3 firstPoint,
  526.             Vector3 center = default(Vector3), Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)
  527.         {
  528.             GameObject go = Get(name, true);
  529.             return MakeArc(ref go, angle, pointCount, normal, firstPoint, center, color, startSize, endSize);
  530.         }
  531.         /// <summary>
  532.         /// Make the specified arc line in 3D space. Example usage: <para><code>
  533.         /// /* GameObject turnArc should be a member variable */
  534.         /// Lines.MakeArc(ref turnArc, Vector3.Angle(transform.forward, direction),
  535.         ///     10, Vector3.Cross(transform.forward, direction),
  536.         ///     transform.forward, transform.position, Color.green, 0.1f, 0);
  537.         /// // makes a curve showing the turn from transform.forward to direction
  538.         /// </code></para>
  539.         /// </summary>
  540.         /// <returns>The LineRenderer hosting the line</returns>
  541.         /// <param name="lineObject">GameObject host of the LineRenderer</param>
  542.         /// <param name="color">Color of the line</param>
  543.         /// <param name="center">Center of arc</param>
  544.         /// <param name="normal">surface-normal of arc's plane</param>
  545.         /// <param name="firstPoint">Arc start, rotate about Vector3.zero</param>
  546.         /// <param name="angle">2D angle. Tip: Vector3.Angle(v1, v2)</param>
  547.         /// <param name="pointCount">How many vertices to make &gt; 1</param>
  548.         /// <param name="startSize">How wide the line is at the start</param>
  549.         /// <param name="endSize">How wide the line is at the end</param>
  550.         public static LineRenderer MakeArc(ref GameObject lineObj,
  551.             float angle, int pointCount, Vector3 normal, Vector3 firstPoint,
  552.             Vector3 center = default(Vector3), Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)
  553.         {
  554.             Vector3[] points = null;
  555.             WriteArc(ref points, pointCount, normal, firstPoint, angle, center);
  556.             return Make(ref lineObj, points, pointCount, color, startSize, endSize);
  557.         }
  558.  
  559.         [System.Obsolete("use Lines.Make(name).Orbital instead, it's more performant.")]
  560.         public static LineRenderer MakeLineOnSphere(string name, Vector3 sphereCenter, Vector3 start, Vector3 end,
  561.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, int pointCount = 24)
  562.         {
  563.             GameObject go = Get(name, true);
  564.             return MakeLineOnSphere(ref go, sphereCenter, start, end, color, startSize, endSize, pointCount);
  565.         }
  566.         public static LineRenderer MakeLineOnSphere(ref GameObject lineObj, Vector3 sphereCenter, Vector3 start, Vector3 end,
  567.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, int pointCount = 24)
  568.         {
  569.             Vector3[] points = null;
  570.             WriteArcOnSphere(ref points, pointCount, sphereCenter, start, end);
  571.             return Make(ref lineObj, points, pointCount, color, startSize, endSize);
  572.         }
  573.  
  574.         public static void WriteArcOnSphere(ref Vector3[] points, int pointCount, Vector3 sphereCenter, Vector3 start, Vector3 end)
  575.         {
  576.             Vector3 axis;
  577.             if (start == -end)
  578.             {
  579.                 axis = (start != Vector3.up && end != Vector3.up) ? Vector3.up : Vector3.right;
  580.             } else
  581.             {
  582.                 axis = Vector3.Cross(start, end).normalized;
  583.             }
  584.             Vector3 a = start - sphereCenter, b = end - sphereCenter;
  585.             float arad = a.magnitude, brad = b.magnitude, angle = 0;
  586.             if (arad != 0 && brad != 0)
  587.             {
  588.                 a /= arad; b /= brad;
  589.                 angle = Vector3.Angle(a, b);
  590.                 if (float.IsNaN(angle)) { angle = 0; }
  591.             }
  592.             WriteArc(ref points, pointCount, axis, a, angle, Vector3.zero);
  593.             float raddelta = brad - arad;
  594.             for (int i = 0; i < points.Length; ++i)
  595.             {
  596.                 points[i] = points[i] * ((i * raddelta / points.Length) + arad);
  597.                 points[i] += sphereCenter;
  598.             }
  599.         }
  600.  
  601.         [System.Obsolete("use Lines.Make(name).Circle instead, it's more performant.")]
  602.         public static LineRenderer MakeCircle(string name, Vector3 center, Vector3 normal,
  603.             Color color = default(Color), float radius = LINESIZE, int pointCount = 0, float lineSize = LINESIZE)
  604.         {
  605.             GameObject go = Get(name, true);
  606.             return MakeCircle(ref go, center, normal, color, radius, pointCount, lineSize);
  607.         }
  608.         /// <summary>Makes a circle with a 3D line</summary>
  609.         /// <returns>The LineRenderer hosting the line</returns>
  610.         /// <param name="lineObj">GameObject host of the LineRenderer</param>
  611.         /// <param name="color">Color of the line</param>
  612.         /// <param name="center">Absolute world-space 3D coordinate</param>
  613.         /// <param name="normal">Which way the circle is facing</param>
  614.         /// <param name="radius"></param>
  615.         /// <param name="pointCount">How many points to use for the circle. If zero, will do 24*PI*r</param>
  616.         /// <param name="linesize">The width of the line</param>
  617.         public static LineRenderer MakeCircle(ref GameObject lineObj, Vector3 center, Vector3 normal,
  618.             Color color = default(Color), float radius = 1, int pointCount = 0, float lineSize = LINESIZE)
  619.         {
  620.             Vector3[] points = null;
  621.             WriteCircle(ref points, center, normal, radius, pointCount);
  622.             LineRenderer lr = Lines.Make(ref lineObj, points, points.Length, color, lineSize, lineSize);
  623.             lr.loop = true;
  624.             return lr;
  625.         }
  626.  
  627.         public static int WriteCircle(ref Vector3[] points, Vector3 center, Vector3 normal, float radius = 1, int pointCount = 0)
  628.         {
  629.             if (pointCount == 0)
  630.             {
  631.                 pointCount = (int)Mathf.Round(24 * 3.14159f * radius + 0.5f);
  632.                 if (points != null)
  633.                 {
  634.                     pointCount = Mathf.Min(points.Length, pointCount);
  635.                 }
  636.             }
  637.             Vector3 crossDir = (normal == Vector3.up || normal == Vector3.down) ? Vector3.forward : Vector3.up;
  638.             Vector3 r = Vector3.Cross(normal, crossDir).normalized;
  639.             WriteArc(ref points, pointCount, normal, r * radius, 360, center);
  640.             return pointCount;
  641.         }
  642.  
  643.         public static LineRenderer MakeSphere(string name, float radius = 1,
  644.             Vector3 center = default(Vector3), Color color = default(Color), float linesize = LINESIZE)
  645.         {
  646.             GameObject go = Get(name, true);
  647.             return MakeSphere(ref go, radius, center, color, linesize);
  648.         }
  649.         /// <returns>a line renderer in the shape of a sphere made of 3 circles, for the x.y.z axis</returns>
  650.         /// <param name="lineObj">Line object.</param>
  651.         /// <param name="radius">Radius.</param>
  652.         /// <param name="center">Center.</param>
  653.         /// <param name="color">Color.</param>
  654.         /// <param name="linesize">Linesize.</param>
  655.         public static LineRenderer MakeSphere(ref GameObject lineObj, float radius = 1,
  656.             Vector3 center = default(Vector3), Color color = default(Color), float linesize = LINESIZE)
  657.         {
  658.             Vector3[] circles = new Vector3[24 * 3];
  659.             Lines.WriteArc(ref circles, 24, Vector3.forward, Vector3.up, 360, center, 24 * 0);
  660.             Lines.WriteArc(ref circles, 24, Vector3.right, Vector3.up, 360, center, 24 * 1);
  661.             Lines.WriteArc(ref circles, 24, Vector3.up, Vector3.forward, 360, center, 24 * 2);
  662.             if (radius != 1) { for (int i = 0; i < circles.Length; ++i) { circles[i] *= radius; } }
  663.             return Lines.Make(ref lineObj, circles, circles.Length, color, linesize, linesize);
  664.         }
  665.  
  666.         [System.Obsolete("use Lines.Make(name).Box instead, it's more performant.")]
  667.         public static LineRenderer MakeBox(string name, Vector3 center,
  668.             Vector3 size, Quaternion rotation, Color color = default(Color), float linesize = LINESIZE)
  669.         {
  670.             GameObject go = Get(name, true);
  671.             return MakeBox(ref go, center, size, rotation, color, linesize);
  672.         }
  673.         public static LineRenderer MakeBox(ref GameObject lineObj, Vector3 center,
  674.             Vector3 size, Quaternion rotation, Color color = default(Color), float linesize = LINESIZE)
  675.         {
  676.             Vector3 y = Vector3.up / 2 * size.y;
  677.             Vector3 x = Vector3.right / 2 * size.x;
  678.             Vector3 z = Vector3.forward / 2 * size.z;
  679.             Vector3[] line = new Vector3[] {
  680.                  z+y-x, -z+y-x, -z-y-x, -z-y+x, -z+y+x,  z+y+x,  z-y+x,  z-y-x,
  681.                  z+y-x,  z+y+x,  z-y+x, -z-y+x, -z+y+x, -z+y-x, -z-y-x,  z-y-x
  682.             };
  683.             for (int i = 0; i < line.Length; ++i) { line[i] = rotation * line[i] + center; }
  684.             LineRenderer lr = Make(ref lineObj, line, line.Length, color, linesize, linesize);
  685.             lr.numCornerVertices = 4;
  686.             return lr;
  687.         }
  688.  
  689.         public static LineRenderer MakeMapPin(string name, Color c = default(Color), float size = 1, float lineWidth = 0.1f)
  690.         {
  691.             GameObject go = Get(name, true);
  692.             return MakeMapPin(ref go, c, size, lineWidth);
  693.         }
  694.         private static Vector3[] mapPin_points_base = null;
  695.         /// <summary>Draws a "map pin", which shows a visualization for direction and orientation</summary>
  696.         /// <returns>The LineRenderer hosting the map pin line. The LineRenderer's transform can be adjusted!</returns>
  697.         /// <param name="lineObj">Line object.</param>
  698.         /// <param name="c">C: color</param>
  699.         /// <param name="size">Size: radius of the map pin</param>
  700.         /// <param name="lineWidth">Line width.</param>
  701.         public static LineRenderer MakeMapPin(ref GameObject lineObj, Color c = default(Color), float size = 1, float lineWidth = 0.1f)
  702.         {
  703.             const float epsilon = 1 / 1024.0f;
  704.             if (mapPin_points_base == null)
  705.             {
  706.                 Vector3 pstn = Vector3.zero, fwrd = Vector3.forward * size, rght = Vector3.right * size, up__ = Vector3.up;
  707.                 float startAngle = (360.0f / 4) - (360.0f / 32);
  708.                 Vector3 v = Quaternion.AngleAxis(startAngle, up__) * fwrd;
  709.                 Lines.WriteArc(ref mapPin_points_base, 32, up__, v, 360, pstn);
  710.                 Vector3 tip = pstn + fwrd * Mathf.Sqrt(2);
  711.                 mapPin_points_base[0] = mapPin_points_base[mapPin_points_base.Length - 1];
  712.                 int m = (32 * 5 / 8) + 1;
  713.                 mapPin_points_base[m++] = mapPin_points_base[m] + (tip - mapPin_points_base[m]) * (1 - epsilon);
  714.                 mapPin_points_base[m++] = tip;
  715.                 int n = (32 * 7 / 8) + 1;
  716.                 while (n < 32) { mapPin_points_base[m++] = mapPin_points_base[n++]; }
  717.                 Vector3 side = pstn + rght;
  718.                 mapPin_points_base[m++] = mapPin_points_base[m] + (side - mapPin_points_base[m]) * (1 - epsilon);
  719.                 mapPin_points_base[m++] = pstn + rght;
  720.                 mapPin_points_base[m++] = pstn + rght * epsilon;
  721.                 mapPin_points_base[m++] = pstn;
  722.                 mapPin_points_base[m++] = pstn + up__ * size * (1 - epsilon);
  723.                 mapPin_points_base[m++] = pstn + up__ * size;
  724.             }
  725.             LineRenderer lr = Lines.Make(ref lineObj, mapPin_points_base, mapPin_points_base.Length, c, lineWidth, lineWidth);
  726.             lr.useWorldSpace = false;
  727.             return lr;
  728.         }
  729.  
  730.         public static LineRenderer SetMapPin(string name, Transform t, Color c = default(Color), float size = 1, float lineWidth = LINESIZE)
  731.         {
  732.             GameObject go = Get(name, true);
  733.             return SetMapPin(ref go, t, c, size, lineWidth);
  734.         }
  735.         /// <summary>Draws a "map pin", which shows a visualization for direction and orientation</summary>
  736.         /// <returns>The LineRenderer hosting the map pin line</returns>
  737.         /// <param name="lineObj">Line object.</param>
  738.         /// <param name="t">t: the transform to attach the map pin visualisation to</param>
  739.         /// <param name="c">C: color</param>
  740.         /// <param name="size">Size: radius of the map pin</param>
  741.         /// <param name="lineWidth">Line width.</param>
  742.         public static LineRenderer SetMapPin(ref GameObject lineObj, Transform t, Color c = default(Color), float size = 1, float lineWidth = LINESIZE)
  743.         {
  744.             LineRenderer line_ = MakeMapPin(ref lineObj, c, size, lineWidth);
  745.             line_.transform.SetParent(t);
  746.             line_.transform.localPosition = Vector3.zero;
  747.             line_.transform.localRotation = Quaternion.identity;
  748.             return line_;
  749.         }
  750.  
  751.         public static Vector3 GetForwardVector(Quaternion q)
  752.         {
  753.             return new Vector3(2 * (q.x * q.z + q.w * q.y),
  754.                 2 * (q.y * q.z + q.w * q.x),
  755.                 1 - 2 * (q.x * q.x + q.y * q.y));
  756.         }
  757.         public static Vector3 GetUpVector(Quaternion q)
  758.         {
  759.             return new Vector3(2 * (q.x * q.y + q.w * q.z),
  760.                 1 - 2 * (q.x * q.x + q.z * q.z),
  761.                 2 * (q.y * q.z + q.w * q.x));
  762.         }
  763.         public static Vector3 GetRightVector(Quaternion q)
  764.         {
  765.             return new Vector3(1 - 2 * (q.y * q.y + q.z * q.z),
  766.                 2 * (q.x * q.y + q.w * q.z),
  767.                 2 * (q.x * q.z + q.w * q.y));
  768.         }
  769.  
  770.         /// <example>CreateSpiralSphere(transform.position, 0.5f, transform.up, transform.forward, 16, 8);</example>
  771.         /// <summary>creates a line spiraled onto a sphere</summary>
  772.         /// <param name="center"></param>
  773.         /// <param name="radius"></param>
  774.         /// <param name="axis">example: Vector3.up</param>
  775.         /// <param name="axisFace">example: Vector3.right</param>
  776.         /// <param name="sides"></param>
  777.         /// <param name="rotations"></param>
  778.         /// <returns></returns>
  779.         public static Vector3[] CreateSpiralSphere(Vector3 center = default(Vector3), float radius = 1,
  780.             Quaternion rotation = default, float sides = 12, float rotations = 6)
  781.         {
  782.             List<Vector3> points = new List<Vector3>(); // List instead of Array because sides and rotations are floats!
  783.             Vector3 axis = Vector3.up;
  784.             Vector3 axisFace = Vector3.right;
  785.             if (sides != 0 && rotations != 0)
  786.             {
  787.                 float iter = 0;
  788.                 float increment = 1f / (rotations * sides);
  789.                 points.Add(center + axis * radius);
  790.                 do
  791.                 {
  792.                     iter += increment;
  793.                     Quaternion faceTurn = Quaternion.AngleAxis(iter * 360 * rotations, axis);
  794.                     Vector3 newFace = faceTurn * axisFace;
  795.                     Quaternion q = Quaternion.LookRotation(newFace);
  796.                     Vector3 right = GetUpVector(q);
  797.                     Vector3 r = right * radius;
  798.                     q = Quaternion.AngleAxis(iter * 180, newFace);
  799.                     r = q * r;
  800.                     r = rotation * r;
  801.                     Vector3 newPoint = center + r;
  802.                     points.Add(newPoint);
  803.                 }
  804.                 while (iter < 1);
  805.             }
  806.             return points.ToArray();
  807.         }
  808.  
  809.         [System.Obsolete("use Lines.Make(name).SpiralSphere instead, it's more performant.")]
  810.         public static LineRenderer MakeSpiralSphere(string name, float radius = 1,
  811.             Vector3 center = default(Vector3), Quaternion rotation = default, Color color = default(Color), float linesize = LINESIZE)
  812.         {
  813.             GameObject go = Get(name, true);
  814.             return MakeSpiralSphere(ref go, radius, center, rotation, color, linesize);
  815.         }
  816.         /// <returns>a line renderer in the shape of a spiraling sphere, spiraling about the Vector3.up axis</returns>
  817.         /// <param name="lineObj">Line object.</param>
  818.         /// <param name="radius">Radius.</param>
  819.         /// <param name="center">Center.</param>
  820.         /// <param name="color">Color.</param>
  821.         /// <param name="linesize">Linesize.</param>
  822.         public static LineRenderer MakeSpiralSphere(ref GameObject lineObj, float radius = 1,
  823.             Vector3 center = default(Vector3), Quaternion rotation = default, Color color = default(Color), float linesize = LINESIZE)
  824.         {
  825.             Vector3[] verts = CreateSpiralSphere(center, radius, rotation, 24, 3);
  826.             return Make(ref lineObj, verts, verts.Length, color, linesize, linesize);
  827.         }
  828.  
  829.         /// <summary>draws the given vector as an arrow</summary>
  830.         /// <param name="name">a unique name for the vector</param>
  831.         /// <param name="vector">math definition of the vector</param>
  832.         /// <param name="color"></param>
  833.         /// <param name="startSize"></param>
  834.         /// <param name="endSize"></param>
  835.         /// <returns></returns>
  836.         [System.Obsolete("use Lines.Make(name).Arrow instead, it's more performant.")]
  837.         public static LineRenderer MakeArrow(string name, Vector3 vector,
  838.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE)
  839.         {
  840.             GameObject go = Get(name, true);
  841.             return MakeArrow(ref go, Vector3.zero, vector, color, startSize, endSize);
  842.         }
  843.         /// <summary>draws the given vector as an arrow</summary>
  844.         /// <param name="name">a unique name for the vector</param>
  845.         /// <param name="start">where the vector should start</param>
  846.         /// <param name="end">where the vector should end</param>
  847.         /// <param name="color"></param>
  848.         /// <param name="startSize"></param>
  849.         /// <param name="endSize"></param>
  850.         /// <returns></returns>
  851.         [System.Obsolete("use Lines.Make(name).Arrow instead, it's more performant.")]
  852.         public static LineRenderer MakeArrow(string name, Vector3 start, Vector3 end,
  853.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  854.         {
  855.             GameObject go = Get(name, true);
  856.             return MakeArrow(ref go, start, end, color, startSize, endSize, arrowHeadSize);
  857.         }
  858.         [System.Obsolete("use Lines.Make(name).Arrow instead, it's more performant.")]
  859.         public static LineRenderer MakeArrow(string name, IList<Vector3> points, int pointCount,
  860.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE, Keyframe[] lineKeyFrames = null)
  861.         {
  862.             GameObject go = Get(name, true);
  863.             return MakeArrow(ref go, points, pointCount, color, startSize, endSize, arrowHeadSize, lineKeyFrames);
  864.         }
  865.  
  866.         public const float ARROWSIZE = 3, LINESIZE = 1f / 8;
  867.         public static LineRenderer MakeArrow(ref GameObject lineObject, Vector3 start, Vector3 end,
  868.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  869.         {
  870.             return MakeArrow(ref lineObject, new Vector3[] { start, end }, 2, color, startSize, endSize, arrowHeadSize);
  871.         }
  872.  
  873.         public static LineRenderer MakeArrow(ref GameObject lineObject, IList<Vector3> points, int pointCount,
  874.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE, Keyframe[] lineKeyFrames = null)
  875.         {
  876.             Vector3[] line;
  877.             Keyframe[] keyframes = CalculateArrowKeyframes(points, pointCount, out line, startSize, endSize, arrowHeadSize, lineKeyFrames);
  878.             LineRenderer lr = Make(ref lineObject, line, line.Length, color, startSize, endSize);
  879.             lr.widthCurve = new AnimationCurve(keyframes);
  880.             return lr;
  881.         }
  882.  
  883.         public static Keyframe[] CalculateArrowKeyframes(IList<Vector3> points, int pointCount, out Vector3[] line,
  884.             float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE, Keyframe[] lineKeyFrames = null)
  885.         {
  886.             float arrowSize = endSize * arrowHeadSize;
  887.             int lastGoodIndex = 0;
  888.             Vector3 arrowheadBase = Vector3.zero, arrowheadWidest = Vector3.zero;
  889.             const float distanceBetweenArrowBaseAndWidePoint = 1.0f / 512;
  890.             Vector3 delta, dir = Vector3.zero;
  891.             // find where, in the list of points, to place the arrowhead
  892.             float dist = 0, extraFromLastGoodIndex = 0;
  893.             for (int i = points.Count - 1; i > 0; --i)
  894.             { // go backwards (from the pointy end)
  895.                 float d = Vector3.Distance(points[i], points[i - 1]);
  896.                 dist += d;
  897.                 // if the arrow direction hasn't been calculated and sufficient distance for the arrowhead has been passed
  898.                 if (dir == Vector3.zero && dist >= arrowSize)
  899.                 {
  900.                     // calculate w,here the arrowheadBase should be (requires 2 points) based on the direction of this segment
  901.                     lastGoodIndex = i - 1;
  902.                     delta = points[i] - points[i - 1];
  903.                     dir = delta.normalized;
  904.                     extraFromLastGoodIndex = dist - arrowSize;
  905.                     arrowheadBase = points[lastGoodIndex] + dir * extraFromLastGoodIndex;
  906.                 }
  907.             }
  908.             // if the line is not long enough for an arrow head, make the whole thing an arrowhead
  909.             if (dist <= arrowSize)
  910.             {
  911.                 line = new Vector3[] { points[0], points[points.Count - 1] };
  912.                 return new Keyframe[] { new Keyframe(0, arrowSize), new Keyframe(1, 0) };
  913.             }
  914.             delta = points[points.Count - 1] - arrowheadBase;
  915.             dir = delta.normalized;
  916.             arrowheadWidest = arrowheadBase + dir * (dist * distanceBetweenArrowBaseAndWidePoint);
  917.             line = new Vector3[lastGoodIndex + 4];
  918.             for (int i = 0; i <= lastGoodIndex; i++)
  919.             {
  920.                 line[i] = points[i];
  921.             }
  922.             line[lastGoodIndex + 3] = points[points.Count - 1];
  923.             line[lastGoodIndex + 2] = arrowheadWidest;
  924.             line[lastGoodIndex + 1] = arrowheadBase;
  925.             Keyframe[] keyframes;
  926.             float arrowHeadBaseStart = 1 - arrowSize / dist;
  927.             float arrowHeadBaseWidest = 1 - (arrowSize / dist - distanceBetweenArrowBaseAndWidePoint);
  928.             if (lineKeyFrames == null)
  929.             {
  930.                 keyframes = new Keyframe[] {
  931.                     new Keyframe(0, startSize), new Keyframe(arrowHeadBaseStart, endSize),
  932.                     new Keyframe(arrowHeadBaseWidest, arrowSize), new Keyframe(1, 0)
  933.                 };
  934.             } else
  935.             {
  936.                 // count how many there are after arrowHeadBaseStart.
  937.                 float t = 0;
  938.                 int validCount = lineKeyFrames.Length;
  939.                 for (int i = 0; i < lineKeyFrames.Length; ++i)
  940.                 {
  941.                     t = lineKeyFrames[i].time;
  942.                     if (t > arrowHeadBaseStart) { validCount = i; break; }
  943.                 }
  944.                 // those are irrelivant now. they'll be replaced by the 3 extra points
  945.                 keyframes = new Keyframe[validCount + 3];
  946.                 for (int i = 0; i < validCount; ++i) { keyframes[i] = lineKeyFrames[i]; }
  947.                 keyframes[validCount + 0] = new Keyframe(arrowHeadBaseStart, endSize);
  948.                 keyframes[validCount + 1] = new Keyframe(arrowHeadBaseWidest, arrowSize);
  949.                 keyframes[validCount + 2] = new Keyframe(1, 0);
  950.             }
  951.             return keyframes;
  952.         }
  953.  
  954.         [System.Obsolete("use Lines.Make(name).Line instead, it's more performant.")]
  955.         public static LineRenderer MakeArrowBothEnds(string name, Vector3 start, Vector3 end,
  956.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  957.         {
  958.             GameObject go = Get(name, true);
  959.             return MakeArrowBothEnds(ref go, start, end, color, startSize, endSize, arrowHeadSize);
  960.         }
  961.         public static LineRenderer MakeArrowBothEnds(ref GameObject lineObject, Vector3 start, Vector3 end,
  962.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  963.         {
  964.             return MakeArrowBothEnds(ref lineObject, new Vector3[] { end, start }, 2, color, startSize, endSize, arrowHeadSize);
  965.         }
  966.         public static LineRenderer MakeArrowBothEnds(ref GameObject lineObject, IList<Vector3> points, int pointCount,
  967.             Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  968.         {
  969.             LineRenderer lr = MakeArrow(ref lineObject, points, pointCount, color, startSize, endSize, arrowHeadSize, null);
  970.             ReverseLineInternal(ref lr);
  971.             Vector3[] p = new Vector3[lr.positionCount];
  972.             lr.GetPositions(p);
  973.             lr = MakeArrow(ref lineObject, p, p.Length, color, endSize, startSize, arrowHeadSize, lr.widthCurve.keys);
  974.             ReverseLineInternal(ref lr);
  975.             return lr;
  976.         }
  977.         public static LineRenderer ReverseLineInternal(ref LineRenderer lr)
  978.         {
  979.             Vector3[] p = new Vector3[lr.positionCount];
  980.             lr.GetPositions(p);
  981.             System.Array.Reverse(p);
  982.             lr.SetPositions(p);
  983.             if (lr.widthCurve != null && lr.widthCurve.length > 1)
  984.             {
  985.                 Keyframe[] kf = new Keyframe[lr.widthCurve.keys.Length];
  986.                 Keyframe[] okf = lr.widthCurve.keys;
  987.                 System.Array.Copy(lr.widthCurve.keys, kf, lr.widthCurve.keys.Length); //for(int i = 0; i<kf.Length; ++i) { kf[i]=okf[i]; }
  988.                 System.Array.Reverse(kf);
  989.                 for (int i = 0; i < kf.Length; ++i) { kf[i].time = 1 - kf[i].time; }
  990.                 lr.widthCurve = new AnimationCurve(kf);
  991.             }
  992.             return lr;
  993.         }
  994.  
  995.         [System.Obsolete("use Lines.Make(name).Arc instead, it's more performant.")]
  996.         public static LineRenderer MakeArcArrow(string name, Vector3 start, Vector3 end, Color color = default(Color), float angle = 90, Vector3 upNormal = default(Vector3),
  997.             float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE, int pointCount = 0)
  998.         {
  999.             GameObject go = Get(name, true);
  1000.             return MakeArcArrow(ref go, start, end, color, angle, upNormal, startSize, endSize, arrowHeadSize, pointCount);
  1001.         }
  1002.         public static LineRenderer MakeArcArrow(ref GameObject lineObj,
  1003.             float angle, int pointCount, Vector3 arcPlaneNormal = default(Vector3), Vector3 firstPoint = default(Vector3),
  1004.             Vector3 center = default(Vector3), Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  1005.         {
  1006.             if (arcPlaneNormal == default(Vector3)) { arcPlaneNormal = Vector3.up; }
  1007.             if (center == default(Vector3) && firstPoint == default(Vector3)) { firstPoint = Vector3.right; }
  1008.             Vector3[] points = null;
  1009.             WriteArc(ref points, pointCount, arcPlaneNormal, firstPoint, angle, center);
  1010.             return MakeArrow(ref lineObj, points, pointCount, color, startSize, endSize, arrowHeadSize);
  1011.         }
  1012.  
  1013.         public static LineRenderer MakeArcArrowBothEnds(ref GameObject lineObj,
  1014.             float angle, int pointCount, Vector3 arcPlaneNormal = default(Vector3), Vector3 firstPoint = default(Vector3),
  1015.             Vector3 center = default(Vector3), Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  1016.         {
  1017.             LineRenderer lr = MakeArcArrow(ref lineObj, angle, pointCount, arcPlaneNormal, firstPoint, center, color, startSize, endSize, arrowHeadSize);
  1018.             ReverseLineInternal(ref lr);
  1019.             Vector3[] p = new Vector3[lr.positionCount];
  1020.             lr.GetPositions(p);
  1021.             lr = MakeArrow(ref lineObj, p, p.Length, color, endSize, startSize, arrowHeadSize, lr.widthCurve.keys);
  1022.             ReverseLineInternal(ref lr);
  1023.             return lr;
  1024.         }
  1025.         [System.Obsolete("use Lines.Make(name).Line instead, it's more performant.")]
  1026.         public static LineRenderer MakeArcArrowBothEnds(string name,
  1027.             float angle, int pointCount, Vector3 arcPlaneNormal = default(Vector3), Vector3 firstPoint = default(Vector3),
  1028.             Vector3 center = default(Vector3), Color color = default(Color), float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  1029.         {
  1030.             GameObject go = Get(name, true);
  1031.             return MakeArcArrowBothEnds(ref go, angle, pointCount, arcPlaneNormal, firstPoint, center, color, startSize, endSize, arrowHeadSize);
  1032.         }
  1033.         public static LineRenderer MakeArcArrow(ref GameObject lineObject, Vector3 start, Vector3 end, Color color = default(Color), float angle = 90, Vector3 upNormal = default(Vector3),
  1034.             float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE, int pointCount = 0)
  1035.         {
  1036.             Vector3[] arc;
  1037.             if (end == start || Mathf.Abs(angle) >= 360)
  1038.             {
  1039.                 arc = new Vector3[] { start, end };
  1040.             } else
  1041.             {
  1042.                 if (upNormal == default) { upNormal = Vector3.up; }
  1043.                 if (pointCount == 0) { pointCount = Mathf.Max((int)(angle * 24 / 180) + 1, 2); }
  1044.                 arc = new Vector3[pointCount];
  1045.                 Vector3 delta = end - start;
  1046.                 float dist = delta.magnitude;
  1047.                 Vector3 dir = delta / dist;
  1048.                 Vector3 right = Vector3.Cross(upNormal, dir).normalized;
  1049.                 WriteArc(ref arc, pointCount, right, -upNormal, angle);
  1050.                 Vector3 arcDelta = arc[arc.Length - 1] - arc[0];
  1051.                 float arcDist = arcDelta.magnitude;
  1052.                 float angleDiff = Vector3.Angle(arcDelta / arcDist, delta / dist);
  1053.                 Quaternion turn = Quaternion.AngleAxis(angleDiff, right);
  1054.                 float ratio = dist / arcDist;
  1055.                 for (int i = 0; i < arc.Length; ++i)
  1056.                 {
  1057.                     arc[i] = (turn * arc[i]) * ratio;
  1058.                 }
  1059.                 Vector3 offset = start - arc[0];
  1060.                 for (int i = 0; i < arc.Length; ++i)
  1061.                 {
  1062.                     arc[i] += offset;
  1063.                 }
  1064.             }
  1065.             return MakeArrow(ref lineObject, arc, arc.Length, color, startSize, endSize, arrowHeadSize);
  1066.         }
  1067.  
  1068.         [System.Obsolete("use Lines.Make(name).Quaternion instead, it's more performant.")]
  1069.         public static void MakeQuaternion(string name, Quaternion q,
  1070.             Vector3 position = default(Vector3), Color color = default(Color), Vector3[] startPoint = null, Quaternion orientation = default(Quaternion),
  1071.             int arcPoints = 24, float lineSize = LINESIZE, float arrowHeadSize = ARROWSIZE)
  1072.         {
  1073.             string axisname = name + "_X";
  1074.             Vector3 axis;
  1075.             float angle;
  1076.             q.ToAngleAxis(out angle, out axis);
  1077.             GameObject axisObj = Get(axisname, true);
  1078.             if (startPoint == null || startPoint.Length == 0)
  1079.             {
  1080.                 startPoint = new Vector3[] {
  1081.                     Vector3.forward, Vector3.up,
  1082.                 };
  1083.             }
  1084.             GameObject[] angleObjects = new GameObject[startPoint.Length];
  1085.             for (int i = 0; i < startPoint.Length; ++i)
  1086.             {
  1087.                 angleObjects[i] = Get(name + "_A" + i, true);
  1088.             }
  1089.             MakeQuaternion(ref axisObj, angleObjects, axis, angle, position, color, orientation, arcPoints, lineSize, arrowHeadSize, startPoint);
  1090.         }
  1091.  
  1092.         public static void MakeQuaternion(ref GameObject axisObj, GameObject[] angleObj, Vector3 axis, float angle,
  1093.             Vector3 position = default(Vector3), Color color = default(Color), Quaternion orientation = default(Quaternion),
  1094.             int arcPoints = 24, float lineSize = LINESIZE, float arrowHeadSize = ARROWSIZE, Vector3[] startPoint = null)
  1095.         {
  1096.             if (angleObj.Length != startPoint.Length) { throw new System.Exception("angleObj and startPoint should be parallel arrays"); }
  1097.             while (angle >= 180) { angle -= 360; }
  1098.             while (angle < -180) { angle += 360; }
  1099.             Vector3 axisRotated = orientation * axis;
  1100.             MakeArrow(ref axisObj, position - axisRotated, position + axisRotated, color, lineSize, lineSize, arrowHeadSize);
  1101.             for (int i = 0; i < angleObj.Length; ++i)
  1102.             {
  1103.                 GameObject aObj = angleObj[i];
  1104.                 MakeArcArrow(ref aObj, angle, arcPoints, axisRotated, startPoint[i], position, color, lineSize, lineSize, arrowHeadSize);
  1105.                 angleObj[i] = aObj;
  1106.             }
  1107.         }
  1108.  
  1109.         // code to draw quaternion with a single line renderer is commented out because it doesn't work right yet.
  1110.         ///// <summary>draws a quaternion with a single line renderer. the visual is very buggy for small angles. Keyframes are finicky.</summary>
  1111.         ///// <param name="lineObject"></param>
  1112.         ///// <param name="axis"></param>
  1113.         ///// <param name="angle"></param>
  1114.         ///// <param name="color"></param>
  1115.         ///// <param name="start"></param>
  1116.         ///// <param name="forwardNormal"></param>
  1117.         ///// <param name="startSize"></param>
  1118.         ///// <param name="endSize"></param>
  1119.         ///// <param name="arrowHeadSize"></param>
  1120.         ///// <param name="pointCount"></param>
  1121.         ///// <returns></returns>
  1122.         //public static LineRenderer MakeQuaternion(ref GameObject lineObject, Vector3 axis, float angle = 90, Color color = default(Color),
  1123.         //  Vector3 start = default(Vector3), Vector3 forwardNormal = default(Vector3),
  1124.         //  float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE, int pointCount = 0) {
  1125.         //  Vector3[] arc;
  1126.         //  if(forwardNormal == default(Vector3)) {
  1127.         //      if(axis == Vector3.forward || axis == Vector3.back) { forwardNormal = Vector3.up; }
  1128.         //      else { forwardNormal = Vector3.forward; }
  1129.         //  }
  1130.         //  if(pointCount == 0) { pointCount = Mathf.Max((int)((angle * 24) / 180)+1, 2); }
  1131.         //  //Debug.Log(angle + " " + pointCount);
  1132.         //  arc = new Vector3[pointCount+6];
  1133.         //  Vector3 right = Vector3.Cross(forwardNormal, axis).normalized;
  1134.         //  WriteArc(ref arc, pointCount, axis, right, angle);
  1135.         //  System.Array.Reverse(arc, 0, pointCount);
  1136.         //  for(int i = 0; i < arc.Length; ++i) {
  1137.         //      arc[i] = arc[i] * .5f + start;
  1138.         //  }
  1139.         //  const float epsilon = (1f / 256);
  1140.         //  arc[pointCount + 0] = arc[pointCount - 1] + (arc[pointCount-1]-arc[pointCount-2]).normalized * epsilon;
  1141.         //  arc[pointCount + 1] = start;
  1142.         //  arc[pointCount + 2] = start - axis / 4;
  1143.         //  arc[pointCount + 3] = start - axis /3;
  1144.         //  arc[pointCount + 4] = start - axis /2;
  1145.         //  arc[pointCount + 5] = start + axis /2;
  1146.         //  LineRenderer lr = MakeArrowBothEnds(ref lineObject, arc, arc.Length, color, startSize, endSize, arrowHeadSize);
  1147.         //  // calculate where to lower the width of the bridge connecting the axis and angle
  1148.         //  float connectionSegmentStart = 0, connectionSegmentEnd = 0, totalDistance = 0;
  1149.         //  int angleBeginIndex = arc.Length - 6;
  1150.         //  int axisEndIndex = arc.Length - 3;
  1151.         //  for(int i = 1; i < angleBeginIndex; ++i) {
  1152.         //      float d = Vector3.Distance(arc[i], arc[i-1]);
  1153.         //      connectionSegmentStart += d;
  1154.         //  }
  1155.         //  connectionSegmentEnd += connectionSegmentStart;
  1156.         //  for(int i = angleBeginIndex; i < axisEndIndex; ++i) {
  1157.         //      float d = Vector3.Distance(arc[i], arc[i-1]);
  1158.         //      connectionSegmentEnd += d;
  1159.         //  }
  1160.         //  totalDistance += connectionSegmentEnd;
  1161.         //  for(int i = axisEndIndex; i < arc.Length; ++i) {
  1162.         //      float d = Vector3.Distance(arc[i], arc[i-1]);
  1163.         //      totalDistance += d;
  1164.         //  }
  1165.         //  //Debug.Log(connectionSegmentStart+" < "+ connectionSegmentEnd+" < "+ totalDistance);
  1166.         //  AnimationCurve ac = lr.widthCurve;
  1167.         //  Keyframe endOfArc = new Keyframe((connectionSegmentStart - epsilon) / totalDistance, startSize);//, 0, -float.MaxValue);
  1168.         //  Keyframe beginningOfBridge = new Keyframe((connectionSegmentStart + epsilon) / totalDistance, 0, -float.MaxValue, 0);
  1169.         //  Keyframe endOfBridge = new Keyframe(connectionSegmentEnd / totalDistance, 0, 0, float.MaxValue);
  1170.         //  Keyframe beginningOfAxis = new Keyframe(connectionSegmentEnd / totalDistance + epsilon, endSize);//, float.MaxValue, 0);
  1171.         //  ac.AddKey(endOfArc);
  1172.         //  ac.AddKey(beginningOfBridge);
  1173.         //  ac.AddKey(endOfBridge);
  1174.         //  ac.AddKey(beginningOfAxis);
  1175.         //  lr.widthCurve = ac;
  1176.         //  return lr;
  1177.         //}
  1178.         //public static LineRenderer MakeQuaternion(ref GameObject lineObject, Quaternion q, Color color = default(Color),
  1179.         //  Vector3 start = default(Vector3), Vector3 fowardNormal = default(Vector3),
  1180.         //  float startSize = LINESIZE, float endSize = LINESIZE, float arrowHeadSize = ARROWSIZE, int pointCount = 0) {
  1181.         //  Vector3 axis;
  1182.         //  float angle;
  1183.         //  q.ToAngleAxis(out angle, out axis);
  1184.         //  return MakeQuaternion(ref lineObject, axis, angle, color, start, fowardNormal, startSize, endSize, arrowHeadSize, pointCount);
  1185.         //}
  1186.  
  1187.         /// <summary>
  1188.         ///
  1189.         /// </summary>
  1190.         /// <param name="rectTransform"></param>
  1191.         /// <param name="x0"></param>
  1192.         /// <param name="y0"></param>
  1193.         /// <param name="x1"></param>
  1194.         /// <param name="y1"></param>
  1195.         /// <param name="col"></param>
  1196.         void DrawLine(RectTransform rectTransform, int x0, int y0, int x1, int y1, Color col)
  1197.         {
  1198.             UnityEngine.UI.RawImage rimg = rectTransform.GetComponent<UnityEngine.UI.RawImage>();
  1199.             if (rimg == null)
  1200.             {
  1201.                 rimg = rectTransform.gameObject.AddComponent<UnityEngine.UI.RawImage>();
  1202.             }
  1203.             if (rimg == null) { throw new System.Exception("unable to create a RawImage on " + rectTransform.name + ", does it already have another renderer?"); }
  1204.             if (rimg.color.a == 0) { Color c = rimg.color; c.a = 1; rimg.color = c; }
  1205.             Texture2D img = rimg.texture as Texture2D;
  1206.             if (img == null)
  1207.             {
  1208.                 Rect r = rectTransform.rect;
  1209.                 img = new Texture2D((int)r.width, (int)r.height);
  1210.                 img.SetPixels(0, 0, (int)r.width, (int)r.height, new Color[(int)(r.width * r.height)]); // set pixels to the default color, which is clear
  1211.                 rimg.texture = img;
  1212.             }
  1213.             DrawLine(img, x0, y0, x1, y1, col);
  1214.             img.Apply();
  1215.         }
  1216.  
  1217.         /// <summary>draws an un-aliased single-pixel line on the given texture with the given color</summary>ne
  1218.         /// <param name="texture"></param>
  1219.         /// <param name="x0"></param>
  1220.         /// <param name="y0"></param>
  1221.         /// <param name="x1"></param>
  1222.         /// <param name="y1"></param>
  1223.         /// <param name="color"></param>
  1224.         void DrawLine(Texture2D texture, int x0, int y0, int x1, int y1, Color color)
  1225.         {
  1226.             int dy = y1 - y0;
  1227.             int dx = x1 - x0;
  1228.             int stepy, stepx;
  1229.             if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
  1230.             if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
  1231.             dy <<= 1;
  1232.             dx <<= 1;
  1233.             float fraction = 0;
  1234.             texture.SetPixel(x0, y0, color);
  1235.             if (dx > dy)
  1236.             {
  1237.                 fraction = dy - (dx >> 1);
  1238.                 while (Mathf.Abs(x0 - x1) > 1)
  1239.                 {
  1240.                     if (fraction >= 0)
  1241.                     {
  1242.                         y0 += stepy;
  1243.                         fraction -= dx;
  1244.                     }
  1245.                     x0 += stepx;
  1246.                     fraction += dy;
  1247.                     texture.SetPixel(x0, y0, color);
  1248.                 }
  1249.             } else
  1250.             {
  1251.                 fraction = dx - (dy >> 1);
  1252.                 while (Mathf.Abs(y0 - y1) > 1)
  1253.                 {
  1254.                     if (fraction >= 0)
  1255.                     {
  1256.                         x0 += stepx;
  1257.                         fraction -= dy;
  1258.                     }
  1259.                     y0 += stepy;
  1260.                     fraction += dx;
  1261.                     texture.SetPixel(x0, y0, color);
  1262.                 }
  1263.             }
  1264.         }
  1265.     }
  1266. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top