Advertisement
medvedya

SpriteDeformerTools

Sep 1st, 2015
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 37.68 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using UnityEngine.Sprites;
  4.  
  5. namespace Medvedya.SpriteDeformerTools
  6. {
  7.     public enum MainToolBarInspector { STANDART, EDIT_VERTICS, EDIT_BOUNDS, EDIT_COLOR };
  8.  
  9.     public abstract class SpriteDeformer : MonoBehaviour, ISerializationCallbackReceiver
  10.     {
  11.         /// <summary>
  12.         /// Polygon of border points
  13.         /// </summary>
  14.         [System.Serializable]
  15.         public class PolygonBorderPath
  16.         {
  17.             /// <summary>                  
  18.             /// Indexes of points from SpriteDeformer.points
  19.             /// </summary>
  20.             public int[] points;
  21.         }
  22.         /// <summary>
  23.         /// All border paths
  24.         /// </summary>
  25.         public List<PolygonBorderPath> borderPaths = new List<PolygonBorderPath>();
  26. #if UNITY_EDITOR
  27.         public SpriteDeformerEditorSaver editorProps = new SpriteDeformerEditorSaver();
  28. #endif
  29.  
  30.  
  31.         /// <summary>
  32.         /// Current MeshRenderer
  33.         /// </summary>
  34.         public MeshRenderer meshRender
  35.         {
  36.             get
  37.             {
  38.                 if (_meshRender == null) _meshRender = GetComponent<MeshRenderer>();
  39.                 return _meshRender;
  40.             }
  41.         }
  42.  
  43.         private MeshRenderer _meshRender;
  44.  
  45.         /// <summary>
  46.         /// Current sprite, if you set it, the mesh will be builded when unity call Update.
  47.         /// </summary>
  48.         public virtual Sprite sprite
  49.         {
  50.             get
  51.             {
  52.                 return _sprite;
  53.             }
  54.             set
  55.             {
  56.                 if (_sprite == value) return;
  57.                 onSpriteChange(_sprite, value);
  58.                 _sprite = value;
  59.                 _lastSprite = value;
  60.                 dirty_sprite = true;
  61.                 if (!Application.isPlaying)
  62.                 {
  63.                     Update();
  64.                 }
  65.                 RecalculateSpriteInfo();
  66.             }
  67.         }
  68.         [SerializeField]
  69.         private Sprite _sprite;
  70.         private Sprite _lastSprite;
  71.  
  72.         private Rect lastSpriteRect;
  73.         private Bounds lastSpriteBounds;
  74.  
  75.  
  76.         /// <summary>
  77.         /// List of all points.
  78.         /// </summary>
  79. #if UNITY_EDITOR
  80.         public IList<SpritePoint> points { get { return _points.AsReadOnly(); } }
  81. #else
  82.         public List<SpritePoint> points { get{return _points;} }
  83. #endif
  84.         [SerializeField]
  85.         private List<SpritePoint> _points = new List<SpritePoint>();
  86.  
  87.         /// <summary>
  88.         /// Bounds of mesh, it will set immediate.
  89.         /// </summary>
  90.         public Bounds bounds
  91.         {
  92.             get { return _bounds; }
  93.             set
  94.             {
  95.                 //if (value == _bounds) return;
  96.                 {
  97.                     _bounds = value;
  98.                     if (mesh != null)
  99.                         mesh.bounds = value;
  100.                     //Debug.Log(mesh);
  101.                 }
  102.             }
  103.         }
  104.         [SerializeField]
  105.         private Bounds _bounds = new Bounds(Vector3.zero, new Vector3(1, 1, 1));
  106. #if UNITY_EDITOR
  107.         /// <summary>
  108.         /// List of all edges.
  109.         /// </summary>
  110.         public IList<Edge> edges { get { return _edges.AsReadOnly(); } }
  111. #else
  112.         public List<Edge> edges { get{ return _edges;} }
  113. #endif
  114.         private List<Edge> _edges = new List<Edge>();
  115.         [SerializeField]
  116.         private Mesh mesh;
  117.  
  118.         protected Vector2 spriteUVposition;
  119.         protected Vector2 spriteUVSize;
  120.         private Vector2 spriteSizeInUnites;
  121.         private Vector2 spritePivotInUnites;
  122.  
  123.         /// <summary>
  124.         /// if it's true, next Update it will calculate sprite information for current generation of mesh.
  125.         /// </summary>
  126.         [System.NonSerialized]
  127.         public bool dirty_sprite = false;
  128.  
  129.         /// <summary>
  130.         /// If it's true, next Update it will calculate new vertexes for mesh.
  131.         /// </summary>
  132.         [System.NonSerialized]
  133.         public bool dirty_offset = false;
  134.         /// <summary>
  135.         /// If it's true, next Update will triangulete and calculate new borderPaths and new trises of mesh.
  136.         /// </summary>
  137.         [System.NonSerialized]
  138.         public bool dirty_tris = false;
  139.         /// <summary>
  140.         /// If it's true and generate collider is on, next FixedUpdate PolygonCollider 2D will change.
  141.         /// </summary>
  142.         [System.NonSerialized]
  143.         public bool dirty_collider = false;
  144.         /// <summary>
  145.         /// If it's true, next Update it will calculate new UVs for mesh.
  146.         /// </summary>
  147.         [System.NonSerialized]
  148.         public bool dirty_uv = false;
  149.         /// <summary>
  150.         /// If it's true, next Update it will calculate new colors for mesh.
  151.         /// </summary>
  152.         [System.NonSerialized]
  153.         public bool dirty_color = false;
  154.         /// <summary>
  155.         /// If it's true, next Update it will calculate new normals for mesh.
  156.         /// </summary>
  157.         [System.NonSerialized]
  158.         public bool dirty_normals = false;
  159.         /// <summary>
  160.         /// if it's true, triangulation will use offset from SpritePoint.
  161.         /// </summary>
  162.         public bool triangulateWithOffsetPosition
  163.         {
  164.             get { return _triangulateWithOffsetPosition; }
  165.             set
  166.             {
  167.                 if (value == _triangulateWithOffsetPosition) return;
  168.                 _triangulateWithOffsetPosition = value;
  169.                 dirty_tris = true;
  170.                 if (!Application.isPlaying)
  171.                 {
  172.                     UpdateMeshImmediate();
  173.                 }
  174.             }
  175.         }
  176.         [SerializeField]
  177.         private bool _triangulateWithOffsetPosition = false;
  178.  
  179.         [SerializeField]
  180.         protected Vector2[] mesh_uvs;
  181.         [SerializeField]
  182.         protected Vector3[] mesh_vertecs;
  183.         [SerializeField]
  184.         protected int[] mesh_triangles;
  185.         [SerializeField]
  186.         protected Vector3[] mesh_normals;
  187.         [SerializeField]
  188.         protected Color[] mesh_colors;
  189.  
  190.         /// <summary>
  191.         /// Scale of sprite, if change it then dirty_points set as true and next Update will generate new vertices.
  192.         /// </summary>
  193.         public Vector2 scale
  194.         {
  195.             get
  196.             {
  197.                 return _scale;
  198.             }
  199.             set
  200.             {
  201.                 if (value == _scale) return;
  202.                 _scale = value;
  203.                 dirty_offset = true;
  204.                 _lastScale = value;
  205.             }
  206.         }
  207.         [SerializeField]
  208.         private Vector2 _scale = new Vector2(1, 1);
  209.         private Vector2 _lastScale;
  210.  
  211.         /// <summary>
  212.         /// It set transform.LocalScale as Vector3 of "1,1,1" and calculate new SpriteDeformer.scale.
  213.         /// </summary>
  214.         public void FreezeScale()
  215.         {
  216.             Vector3 sc = transform.localScale;
  217.             if (sc != new Vector3(1, 1, 1))
  218.             {
  219.                 scale = Vector2.Scale(sc, scale);
  220.                 transform.localScale = new Vector3(1, 1, 1);
  221.             }
  222.  
  223.         }
  224.         /// <summary>
  225.         ///Create new unique mesh. The old mesh form MeshFilter will not be destroyed.
  226.         /// </summary>
  227.         public void CreateNewMesh(bool destoryOldMesh = false)
  228.         {
  229.             mesh = new Mesh();
  230.             MeshFilter mf = GetComponent<MeshFilter>();
  231.             if (mf.sharedMesh != null && destoryOldMesh) DestroyImmediate(mf.sharedMesh);
  232.             if (!Application.isPlaying)
  233.                 mf.sharedMesh = mesh;
  234.             else
  235.                 mf.mesh = mesh;
  236.         }
  237.         /// <summary>
  238.         /// Clear list of points.
  239.         /// </summary>
  240.         public void ClearPoints()
  241.         {
  242.             while (points.Count > 0)
  243.             {
  244.                 RemovePoint(points[0]);
  245.  
  246.             }
  247.  
  248.         }
  249.         /// <summary>
  250.         /// Clear list of edges.
  251.         /// </summary>
  252.         public void ClearEdges()
  253.         {
  254.             while (_edges.Count > 0)
  255.             {
  256.                 _edges.Clear();
  257.             }
  258.             dirty_tris = true;
  259.         }
  260.         /// <summary>
  261.         /// Remove all points and edges and create new topology as rectangle.
  262.         /// </summary>
  263.         public void SetRectanglePoints()
  264.         {
  265.             ClearEdges();
  266.             ClearPoints();
  267.             SpritePoint upLeft = new SpritePoint(0, 1);
  268.             SpritePoint downLeft = new SpritePoint(0, 0);
  269.             SpritePoint upRight = new SpritePoint(1, 1);
  270.             SpritePoint downRight = new SpritePoint(1, 0);
  271.             AddPoint(upLeft); AddPoint(downLeft); AddPoint(upRight); AddPoint(downRight);
  272.  
  273.             AddEdge(new Edge(upLeft, upRight));
  274.             AddEdge(new Edge(upRight, downRight));
  275.             AddEdge(new Edge(downRight, downLeft));
  276.             AddEdge(new Edge(downLeft, upLeft));
  277.  
  278.         }
  279.         /// <summary>
  280.         /// Calculate new dependent sprite info for generation mesh.
  281.         /// </summary>
  282.         public void RecalculateSpriteInfo()
  283.         {
  284.             if (sprite == null) return;
  285.            
  286.             if (sprite.packed && sprite.packingMode == SpritePackingMode.Tight)
  287.             {
  288.                 Debug.LogException(new System.Exception("Sprite packer -> TightPackerPolicy is not supported. Please use DefaultPackerPolicy"));
  289.                 return;
  290.             }
  291.             if (Application.isPlaying)
  292.             {
  293.                 spriteUVposition = new Vector2(sprite.textureRect.x / sprite.texture.width, sprite.textureRect.y / sprite.texture.height);
  294.                 spriteUVposition -= new Vector2(sprite.textureRectOffset.x / sprite.texture.width, sprite.textureRectOffset.y / sprite.texture.height);
  295.                 //spriteVUSize = new Vector2(sprite.textureRect.width / sprite.texture.width, sprite.textureRect.height / sprite.texture.height);
  296.                 spriteUVSize = new Vector2(sprite.rect.width / sprite.texture.width, sprite.rect.height / sprite.texture.height);
  297.             }
  298.             else
  299.             {
  300.                 spriteUVposition = new Vector2(sprite.rect.x / sprite.texture.width, sprite.rect.y / sprite.texture.height);
  301.                 spriteUVSize = new Vector2(sprite.rect.width / sprite.texture.width, sprite.rect.height / sprite.texture.height);
  302.             }
  303.            
  304.             spriteSizeInUnites = sprite.rect.size / sprite.pixelsPerUnit;
  305.             spritePivotInUnites = -(sprite.pivot) / sprite.pixelsPerUnit;
  306.  
  307.             //it doesn't work
  308.             //Vector2.Vector4 uv = UnityEngine.Sprites.DataUtility.GetOuterUV(sprite);
  309.             //spriteVUSize = new Vector2(uv.w, uv.z);
  310.             //spriteUVposition = new Vector2(uv.x, uv.y);
  311.         }
  312.         protected Triangulator triangulator;
  313.  
  314.         protected void tringulate()
  315.         {
  316.             if (triangulator == null)
  317.                 triangulator = new Triangulator(this);
  318.             triangulator.useDeltaPosition = triangulateWithOffsetPosition;
  319.             triangulator.trinagulate();
  320.             borderPaths.Clear();
  321.             foreach (var item in triangulator.bigLoops)
  322.             {
  323.                 PolygonBorderPath newP = new PolygonBorderPath();
  324.                 borderPaths.Add(newP);
  325.                 List<int> pointList = new List<int>();
  326.                 foreach (var item2 in item.edgeNodes)
  327.                 {
  328.                     pointList.Add(item2.index);
  329.                 }
  330.                 newP.points = pointList.ToArray();
  331.             }
  332.         }
  333.         protected virtual void generateMeshData(bool new_tringulate, bool new_uv, bool new_points, bool new_color, bool new_normals)
  334.         {
  335.             if (new_points || new_color || new_uv || new_normals)
  336.             {
  337.                 if (new_normals) mesh_normals = new Vector3[points.Count];
  338.                 if (new_color) mesh_colors = new Color[points.Count];
  339.                 if (new_points) mesh_vertecs = new Vector3[points.Count];
  340.                 if (new_uv) mesh_uvs = new Vector2[points.Count];
  341.                 for (int i = 0; i < points.Count; i++)
  342.                 {
  343.                     SpritePoint cp = points[i];
  344.                     if (new_points)
  345.                     {
  346.                         Vector3 v3 = SpritePositionToLocal(GetSpritePositionOfSpritePoint(cp));
  347.                         v3.z = cp.offsets[0].z;
  348.                         mesh_vertecs[i] = v3;
  349.                     }
  350.                     //if (new_normals) mesh_normals[i] = Vector3.forward;
  351.                     if (new_normals) mesh_normals[i] = Vector3.back;
  352.                     if (new_color) mesh_colors[i] = cp.color;
  353.                     if (new_uv)
  354.                     {
  355.                         mesh_uvs[i] = Vector2.Scale(spriteUVSize, cp.spritePosition) + spriteUVposition;
  356.                     }
  357.                 }
  358.             }
  359.  
  360.             if (new_tringulate)
  361.             {
  362.                 tringulate();
  363.                 mesh_triangles = triangulator.intTriangles;
  364.             }
  365.         }
  366.         protected void setMeshDataToMesh(bool new_tringulate, bool new_uv, bool new_points, bool new_color, bool new_normals)
  367.         {
  368.             if (mesh == null) return;
  369.             if (new_tringulate) mesh.Clear();
  370.             if (new_tringulate || new_points)
  371.             {
  372.                 mesh.MarkDynamic();
  373.                 mesh.vertices = mesh_vertecs;
  374.             }
  375.             if (new_tringulate || new_normals) mesh.normals = mesh_normals;
  376.             if (new_tringulate || new_uv) mesh.uv = mesh_uvs;
  377.             if (new_tringulate) mesh.triangles = mesh_triangles;
  378.             if (new_tringulate || new_color) mesh.colors = mesh_colors;
  379.            
  380.         }
  381.  
  382.         /// <summary>
  383.         /// Divide the edge.
  384.         /// </summary>
  385.         /// <param name="ed"></param>
  386.         /// <param name="autoOffset"></param>
  387.         /// <returns></returns>
  388.         public SpritePoint DivedeEdge(EdgeDivider ed, bool autoOffset = false)
  389.         {
  390.             SpritePoint newPoint = new SpritePoint(ed.position);
  391.             Edge e1 = new Edge(ed.edge.point1, newPoint);
  392.             Edge e2 = new Edge(newPoint, ed.edge.point2);
  393.             AddPoint(newPoint);
  394.             AddEdge(e1);
  395.             AddEdge(e2);
  396.             if (autoOffset)
  397.             {
  398.                 float d1 = Vector2.Distance(ed.edge.point1.spritePosition, ed.position);
  399.                 float d2 = Vector2.Distance(ed.edge.point2.spritePosition, ed.position);
  400.                 float ds = d1 + d2;
  401.                 float w1 = d1 / ds;
  402.                 Vector2 np = Vector2.Lerp(ed.edge.point1.spritePosition + ed.edge.point1.offset2d,
  403.                     ed.edge.point2.spritePosition + ed.edge.point2.offset2d, w1);
  404.                 newPoint.offset2d = np - newPoint.spritePosition;
  405.             }
  406.             RemoveEdge(ed.edge);
  407.             return newPoint;
  408.         }
  409.  
  410.         /// <summary>
  411.         /// Add edge to the topology and set true to dirty_tris.
  412.         /// </summary>
  413.         /// <param name="e"></param>
  414.         public void AddEdge(Edge e)
  415.         {
  416.             _edges.Add(e);
  417.             dirty_tris = true;
  418.         }
  419.         /// <summary>
  420.         /// Get closet edge and get the point for splitting in "EdgeDivider".
  421.         /// </summary>
  422.         /// <param name="spritePos">sprite position</param>
  423.         /// <param name="without">Edges wll not be used</param>
  424.         /// <returns></returns>
  425.         public EdgeDivider GetClosestEdge(Vector2 spritePos, Edge[] without = null)
  426.         {
  427.             EdgeDivider ed = new EdgeDivider();
  428.             float minDis = float.MaxValue;
  429.             List<Edge> wo = null;
  430.             if (without != null)
  431.             {
  432.                 wo = new List<Edge>(without);
  433.             }
  434.             foreach (Edge edge in edges)
  435.             {
  436.                 if (without != null && wo.Contains(edge))
  437.                 {
  438.                     continue;
  439.                 }
  440.                 Vector2 v = edge.GetClosest(spritePos);
  441.                 float d = Vector2.Distance(spritePos, v);
  442.                 if (d < minDis)
  443.                 {
  444.                     minDis = d;
  445.                     ed.edge = edge;
  446.                     ed.position = v;
  447.                 }
  448.             }
  449.             return ed;
  450.         }
  451.         /// <summary>
  452.         /// Get all edges what have this SpritePoint.
  453.         /// </summary>
  454.         /// <param name="p"></param>
  455.         /// <returns></returns>
  456.         public List<Edge> GetEdgesWithPoint(SpritePoint p)
  457.         {
  458.             List<Edge> edgesp = new List<Edge>();
  459.             foreach (Edge e in edges)
  460.             {
  461.                 if (e.ContainsPoint(p))
  462.                 {
  463.                     edgesp.Add(e);
  464.                 }
  465.             }
  466.             return edgesp;
  467.         }
  468.         /// <summary>
  469.         ///  Get the edge which have this SpritePoints.
  470.         /// </summary>
  471.         /// <param name="p"></param>
  472.         /// <param name="p2"></param>
  473.         /// <returns></returns>
  474.         public Edge GetEdgeWithTwoPoints(SpritePoint p, SpritePoint p2)
  475.         {
  476.             foreach (Edge e in edges)
  477.             {
  478.                 if (e.ContainsPoint(p) && e.ContainsPoint(p2))
  479.                 {
  480.                     return e;
  481.                 }
  482.             }
  483.             return null;
  484.         }
  485.         /// <summary>
  486.         ///  Get all edges what be connected this edge.
  487.         /// </summary>
  488.         /// <param name="edge"></param>
  489.         /// <returns></returns>
  490.         public List<Edge> GetEdgesWithEdge(Edge edge)
  491.         {
  492.             List<Edge> res = new List<Edge>();
  493.             foreach (var item in edges)
  494.             {
  495.                 if (item.ContainsPoint(edge.point1) || item.ContainsPoint(edge.point2))
  496.                 {
  497.                     res.Add(item);
  498.                 }
  499.             }
  500.             return res;
  501.         }
  502.  
  503.         public List<SpritePoint> GetСonnectedPoint(SpritePoint point, string pointName = "")
  504.         {
  505.             List<SpritePoint> res = new List<SpritePoint>();
  506.             List<Edge> es = GetEdgesWithPoint(point);
  507.             foreach (var item in es)
  508.             {
  509.                 if (item.ContainsPoint(point))
  510.                 {
  511.                     SpritePoint otherPoint = item.point1 == point ? item.point2 : item.point1;
  512.                     if (pointName == "" || pointName == otherPoint.name)
  513.                     {
  514.                         res.Add(otherPoint);
  515.                     }
  516.                 }
  517.             }
  518.  
  519.             return res;
  520.         }
  521.         /// <summary>
  522.         /// Is any edge with this points contains.
  523.         /// </summary>
  524.         /// <param name="p1"></param>
  525.         /// <param name="p2"></param>
  526.         /// <returns></returns>
  527.         public bool ContainsEdge(SpritePoint p1, SpritePoint p2)
  528.         {
  529.             foreach (Edge e in edges)
  530.             {
  531.                 if (e.point1 == p1 && e.point2 == p2 || e.point1 == p2 && e.point2 == p1) return true;
  532.             }
  533.             return false;
  534.         }
  535.  
  536.         [SerializeField]
  537.         private List<EdgeSerialization> edgeSerializations;
  538.         public void OnBeforeSerialize()
  539.         {
  540.             edgeSerializations = new List<EdgeSerialization>();
  541.             for (int i = 0; i < edges.Count; i++)
  542.             {
  543.                 edgeSerializations.Add(
  544.                     new EdgeSerialization(
  545.                         points.IndexOf(edges[i].point1),
  546.                         points.IndexOf(edges[i].point2)
  547.                         )
  548.                     );
  549.             }
  550. #if UNITY_EDITOR
  551.             editorProps.serelizableSelectedPoints = new int[editorProps.selectedPoints.Count];
  552.             for (int i = 0; i < editorProps.selectedPoints.Count; i++)
  553.             {
  554.                 editorProps.serelizableSelectedPoints[i] = points.IndexOf(editorProps.selectedPoints[i]);
  555.             }
  556. #endif
  557.  
  558.         }
  559.         public void OnAfterDeserialize()
  560.         {
  561.             _edges = new List<Edge>();
  562.             for (int i = 0; i < edgeSerializations.Count; i++)
  563.             {
  564.                 EdgeSerialization ce = edgeSerializations[i];
  565.                 _edges.Add(
  566.                     new Edge(
  567.                         points[ce.point1Index],
  568.                         points[ce.point2index]
  569.                          )
  570.                         );
  571.             }
  572. #if UNITY_EDITOR
  573.             editorProps.selectedPoints = new List<SpritePoint>();
  574.             for (int i = 0; i < editorProps.serelizableSelectedPoints.Length; i++)
  575.             {
  576.                 editorProps.selectedPoints.Add(points[editorProps.serelizableSelectedPoints[i]]);
  577.             }
  578. #endif
  579.         }
  580.  
  581.         public void SetAllDirty(bool dirty_value = true)
  582.         {
  583.             dirty_tris = dirty_value;
  584.             dirty_color = dirty_value;
  585.             dirty_normals = dirty_value;
  586.             dirty_offset = dirty_value;
  587.             dirty_uv = dirty_value;
  588.             dirty_sprite = dirty_value;
  589.         }
  590.         /// <summary>
  591.         /// Add a point to the topology.
  592.         /// </summary>
  593.         /// <param name="point"></param>
  594.         /// <param name="autoOffset"></param>
  595.         public virtual void AddPoint(SpritePoint point, bool autoOffset = false)
  596.         {
  597.             _points.Add(point);
  598.             SetAllDirty();
  599.             if (autoOffset)
  600.             {
  601.                 SpritePoint[] tr = GetTriangleAroundPoint(point);
  602.                 if (tr != null)
  603.                 {
  604.                     Vector2 u1 = tr[0].spritePosition; // get the triangle UVs
  605.                     Vector2 u2 = tr[1].spritePosition; // get the triangle UVs
  606.                     Vector2 u3 = tr[2].spritePosition; // get the triangle UVs
  607.  
  608.                     Vector2 l1 = tr[0].spritePosition + (Vector2)tr[0].offset;
  609.                     Vector2 l2 = tr[1].spritePosition + (Vector2)tr[1].offset;
  610.                     Vector2 l3 = tr[2].spritePosition + (Vector2)tr[2].offset;
  611.  
  612.                     float a = Medvedya.GeometryMath.Triangle.area(u1, u2, u3); if (a == 0f) return;
  613.  
  614.                     float a1 = Medvedya.GeometryMath.Triangle.area(u2, u3, point.spritePosition) / a; if (a1 < 0) return;
  615.                     float a2 = Medvedya.GeometryMath.Triangle.area(u3, u1, point.spritePosition) / a; if (a2 < 0) return;
  616.                     float a3 = Medvedya.GeometryMath.Triangle.area(u1, u2, point.spritePosition) / a; if (a3 < 0) return;
  617.  
  618.                     Vector2 pInObj = a1 * l1 + a2 * l2 + a3 * l3;
  619.  
  620.                     point.offset = pInObj - point.spritePosition;
  621.                 }
  622.             }
  623.         }
  624.         /// <summary>
  625.         /// Get the triangle where the point is, it will work only after triangulation was done.
  626.         /// </summary>
  627.         /// <param name="point"></param>
  628.         /// <returns></returns>
  629.         public SpritePoint[] GetTriangleAroundPoint(SpritePoint point)
  630.         {
  631.             for (int i = 0; i < mesh_triangles.Length; i += 3)
  632.             {
  633.                 int tr0 = mesh_triangles[i];
  634.                 int tr1 = mesh_triangles[i + 1];
  635.                 int tr2 = mesh_triangles[i + 2];
  636.                 if (
  637.                      Medvedya.GeometryMath.Triangle.isBelongOriantByClock(
  638.                      points[tr0].spritePosition,
  639.                      points[tr1].spritePosition,
  640.                      points[tr2].spritePosition, point.spritePosition)
  641.                      )
  642.                 {
  643.                     return new SpritePoint[] { points[tr0], points[tr1], points[tr2] };
  644.                 }
  645.             }
  646.             return null;
  647.         }
  648.         /// <summary>
  649.         /// Sprite position to transform-local position.
  650.         /// </summary>
  651.         /// <param name="spritePosition"></param>
  652.         /// <returns></returns>
  653.         public Vector2 SpritePositionToLocal(Vector2 spritePosition)
  654.         {
  655.             Vector2 p = Vector2.Scale(spritePosition, spriteSizeInUnites) + spritePivotInUnites;
  656.             return Vector2.Scale(p, _scale);
  657.         }
  658.         /// <summary>
  659.         ///  Sprite position to transform position.
  660.         /// </summary>
  661.         /// <param name="spritePosition"></param>
  662.         /// <returns></returns>
  663.         public Vector3 SpritePositionToGlobal(Vector2 spritePosition)
  664.         {
  665.             return transform.TransformPoint(SpritePositionToLocal(spritePosition));
  666.         }
  667.         /// <summary>
  668.         /// Local - transform position to sprite position.
  669.         /// </summary>
  670.         /// <param name="localPosition"></param>
  671.         /// <returns></returns>
  672.         public Vector2 LocalPositionToSpritePosition(Vector2 localPosition)
  673.         {
  674.             Vector2 p = new Vector2(localPosition.x / spriteSizeInUnites.x / _scale.x, localPosition.y / spriteSizeInUnites.y / _scale.y)
  675.                   -
  676.                   new Vector2(spritePivotInUnites.x / spriteSizeInUnites.x, spritePivotInUnites.y / spriteSizeInUnites.y)
  677.                 ;
  678.             return p;
  679.         }
  680.         /// <summary>
  681.         /// Transform position to sprite position.
  682.         /// </summary>
  683.         /// <param name="globalPosition"></param>
  684.         /// <returns></returns>
  685.         public Vector2 GlobalPositionToSpritePosition(Vector3 globalPosition)
  686.         {
  687.             return LocalPositionToSpritePosition(transform.InverseTransformPoint(globalPosition));
  688.         }
  689.  
  690.         /// <summary>
  691.         /// Maximum fps if you use animation, if it's zero the mesh will change every frame.
  692.         /// </summary>
  693.         public float maxFps
  694.         {
  695.             get
  696.             {
  697.                 if (minimumTimeToUpdate == 0) return 0;
  698.                 return 1f / minimumTimeToUpdate;
  699.             }
  700.             set
  701.             {
  702.                 if (value == 0) minimumTimeToUpdate = 0;
  703.                 else
  704.                     minimumTimeToUpdate = 1f / value;
  705.             }
  706.         }
  707.         [SerializeField]
  708.         private float minimumTimeToUpdate = 0;
  709.         private float timeUpdate = 0;
  710.         protected virtual void Update()
  711.         {
  712.             timeUpdate += Time.unscaledDeltaTime;
  713.             if (GetComponent<Renderer>().isVisible && (timeUpdate >= minimumTimeToUpdate || !Application.isPlaying))
  714.             {
  715.                 timeUpdate = 0;
  716.  
  717.                 UpdateMeshImmediate();
  718.             }
  719.             if (!Application.isPlaying)
  720.             {
  721.                 if (sprite != null && (lastSpriteRect != sprite.rect || lastSpriteBounds != sprite.bounds))
  722.                 {
  723.                     lastSpriteRect = sprite.rect;
  724.                     lastSpriteBounds = sprite.bounds;
  725.                     dirty_sprite = true;
  726.                     UpdateMeshImmediate();
  727.                 }
  728.  
  729.             }
  730.         }
  731.         protected virtual void onSpriteChange(Sprite lastSprite, Sprite currentSprite)
  732.         {
  733.  
  734.         }
  735.  
  736.         /// <summary>
  737.         /// Remove a point and all edges with this point and set true to dirty_tris, dirty_points, dirty_uv.
  738.         /// </summary>
  739.         /// <param name="p"></param>
  740.         public virtual void RemovePoint(SpritePoint p)
  741.         {
  742.             SetAllDirty();
  743.             List<Edge> delEdges = new List<Edge>();
  744.             delEdges.AddRange(GetEdgesWithPoint(p));
  745.             foreach (Edge e in delEdges)
  746.             {
  747.                 RemoveEdge(e);
  748.             }
  749.             _points.Remove(p);
  750.  
  751.         }
  752.         /// <summary>
  753.         /// Remove points and all edges with this points.
  754.         /// </summary>
  755.         /// <param name="points"></param>
  756.         public void RemovePoints(SpritePoint[] points)
  757.         {
  758.             foreach (SpritePoint p in points)
  759.             {
  760.                 RemovePoint(p);
  761.             }
  762.         }
  763.         /// <summary>
  764.         /// Remove edge and set true to dirty_tris .
  765.         /// </summary>
  766.         /// <param name="e"></param>
  767.         public void RemoveEdge(Edge e)
  768.         {
  769.             _edges.Remove(e);
  770.             dirty_tris = true;
  771.             dirty_offset = true;
  772.         }
  773.         /// <summary>
  774.         /// Create new edge and add it to list of edges.
  775.         /// </summary>
  776.         /// <param name="p1"></param>
  777.         /// <param name="p2"></param>
  778.         /// <returns>Created edge</returns>
  779.         public Edge CreateEdge(SpritePoint p1, SpritePoint p2)
  780.         {
  781.             Edge newEdge = new Edge(p1, p2);
  782.             _edges.Add(newEdge);
  783.             dirty_tris = true;
  784.             return newEdge;
  785.         }
  786.  
  787.         /// <summary>
  788.         /// Get EdgeDividers is cuting all edges by segmet.
  789.         /// </summary>
  790.         /// <param name="v1"></param>
  791.         /// <param name="v2"></param>
  792.         /// <returns></returns>
  793.         private EdgeDivider[] getCutDivider(Vector2 v1, Vector2 v2)
  794.         {
  795.             List<EdgeDivider> eds = new List<EdgeDivider>();
  796.             foreach (var item in edges)
  797.             {
  798.                 Vector2 op = Vector2.zero;
  799.                 if (
  800.                     Medvedya.GeometryMath.Line.intersection(v1, v2, item.point1.spritePosition, item.point2.spritePosition, out op)
  801.                     )
  802.                 {
  803.                     eds.Add(new EdgeDivider(op, item));
  804.                 }
  805.             }
  806.             return eds.ToArray();
  807.         }
  808.         private void cut(Vector2[] points)
  809.         {
  810.             for (int i = 0; i < points.Length - 1; i++)
  811.             {
  812.                 Vector2 v1 = points[i];
  813.                 Vector2 v2 = points[i + 1];
  814.                 EdgeDivider[] eds = getCutDivider(v1, v2);
  815.                 List<SpritePoint> newPoints = new List<SpritePoint>();
  816.                 foreach (var item in eds)
  817.                 {
  818.                     newPoints.Add(DivedeEdge(item));
  819.                 }
  820.                 newPoints.Sort(
  821.                     (p1, p2)
  822.                         =>
  823.                         Vector2.Distance(v1, p1.spritePosition).CompareTo(Vector2.Distance(v1, p2.spritePosition))
  824.                         );
  825.                 for (int j = 0; j < newPoints.Count - 1; j++)
  826.                 {
  827.                     CreateEdge(newPoints[j], newPoints[j + 1]);
  828.                 }
  829.             }
  830.  
  831.         }
  832.         private void cut(Vector2 v1, Vector2 v2)
  833.         {
  834.             cut(new Vector2[] { v1, v2 });
  835.         }
  836.  
  837.         protected virtual void OnEnable()
  838.         {
  839.             //meshRender.enabled = true;
  840.         }
  841.         protected virtual void OnDisable()
  842.         {
  843.             //meshRender.enabled = false;
  844.         }
  845.         protected virtual void Awake()
  846.         {
  847.             {
  848.                 int newSortedId = 0;
  849.                 int newSortedOrder = 0;
  850.                 bool setSorted = false;
  851.                 SpriteRenderer sr = gameObject.GetComponent<SpriteRenderer>();
  852.                 if (sr != null)
  853.                 {
  854.                     sprite = sr.sprite;
  855.                     SetRectanglePoints();
  856.                     dirty_tris = true;
  857.                     dirty_sprite = true;
  858.                     newSortedId = sr.sortingLayerID;
  859.                     newSortedOrder = sr.sortingOrder;
  860.                     DestroyImmediate(sr);
  861.                     setSorted = true;
  862.  
  863.                 }
  864.                 if (gameObject.GetComponent<MeshRenderer>() == null)
  865.                 {
  866.                     _meshRender = gameObject.AddComponent<MeshRenderer>();
  867.                 }
  868.                 if (gameObject.GetComponent<MeshFilter>() == null) gameObject.AddComponent<MeshFilter>();
  869.                 if (setSorted)
  870.                 {
  871.                     meshRender.sortingLayerID = newSortedId;
  872.                     meshRender.sortingOrder = newSortedOrder;
  873.                 }
  874.             }
  875.  
  876.  
  877.  
  878.             if (!Application.isPlaying)
  879.             {
  880.                 if (sprite != null)
  881.                 {
  882.                     lastSpriteRect = sprite.rect;
  883.                     lastSpriteBounds = sprite.bounds;
  884.                 }
  885.                 SpriteDeformer[] sds = gameObject.GetComponents<SpriteDeformer>();
  886.                 if (sds.Length > 1)
  887.                 {
  888.                     foreach (var item in sds)
  889.                     {
  890.                         if (item != this)
  891.                         {
  892.                             this.sprite = item.sprite;
  893.                             foreach (var atherPoint in item.points)
  894.                             {
  895.                                 this.AddPoint(atherPoint);
  896.                             }
  897.                             foreach (var atherEdge in item.edges)
  898.                             {
  899.                                 this.AddEdge(atherEdge);
  900.                             }
  901.                             DestroyImmediate(item);
  902.                             dirty_tris = true;
  903.                             dirty_offset = true;
  904.                             break;
  905.                         }
  906.                     }
  907.                 }
  908.  
  909.  
  910.  
  911.             }
  912.             RecalculateSpriteInfo();
  913.             dirty_uv = true;
  914.             UpdateMeshImmediate();
  915.             _lastSprite = _sprite;
  916.             _lastScale = _scale;
  917.             CreateNewMesh();
  918.             mesh.bounds = bounds;
  919.             setMeshDataToMesh(true, true, true, true, true);
  920.             if (Application.isPlaying)
  921.             {
  922.                 if (!GetComponent<Renderer>().isVisible)
  923.                 {
  924.                     this.enabled = false;
  925.                 }
  926.             }
  927.         }
  928.         protected virtual void OnDestroy()
  929.         {
  930.             DestroyImmediate(mesh);
  931.         }
  932.         public Vector2 getOffsetPointPositionByGlobalPosition(SpritePoint point, Vector3 globalPosition)
  933.         {
  934.             Vector2 newPointPosition = GlobalPositionToSpritePosition(globalPosition);
  935.             return newPointPosition - point.spritePosition;
  936.         }
  937.  
  938.         /// <summary>
  939.         /// Generate new data for the mesh and set this data to the mesh. It use dirty_* properties and will set all of these as false.
  940.         /// </summary>
  941.         public void UpdateMeshImmediate()
  942.         {
  943.             if (_lastScale != _scale)
  944.             {
  945.                 dirty_offset = true;
  946.                 _lastScale = scale;
  947.             }
  948.             if (_lastSprite != _sprite)
  949.             {
  950.                 dirty_sprite = true;
  951.                 onSpriteChange(_lastSprite, _sprite);
  952.                 _lastSprite = _sprite;
  953.             }
  954.  
  955.             if (dirty_tris || dirty_offset || dirty_sprite || dirty_offset)
  956.             {
  957.                 // Debug.Log("prite:" + dirty_sprite.ToString() + "    new trises:" + dirty_tris.ToString() + "    new UV:" + dirty_uv.ToString() + "    new Points:" + dirty_offset.ToString());
  958.             }
  959.             if (dirty_sprite)
  960.             {
  961.                 RecalculateSpriteInfo();
  962.                 dirty_offset = true;
  963.                 dirty_uv = true;
  964.             }
  965.             if (dirty_tris || dirty_uv || dirty_offset || dirty_color || dirty_normals)
  966.             {
  967.                 generateMeshData(dirty_tris, dirty_uv, dirty_offset, dirty_color, dirty_normals);
  968.                 setMeshDataToMesh(dirty_tris, dirty_uv, dirty_offset, dirty_color, dirty_normals);
  969.                 if (dirty_offset || dirty_uv || dirty_tris) dirty_collider = true;
  970.             }
  971.             SetAllDirty(false);
  972.         }
  973.         /// <summary>
  974.         /// Return sprite postion by SpritePoint.
  975.         /// </summary>
  976.         /// <param name="point"></param>
  977.         /// <returns></returns>
  978.         public virtual Vector2 GetSpritePositionOfSpritePoint(SpritePoint point)
  979.         {
  980.            
  981.             return point.spritePosition + (Vector2)point.offsets[0];
  982.         }
  983.        
  984.         protected void FixedUpdate()
  985.         {
  986.             if (_generateColliderInRunTime && dirty_collider)
  987.             {
  988.                 GenerateCollider();
  989.             }
  990.             dirty_collider = false;
  991.         }
  992.         protected PolygonCollider2D polygonCollider
  993.         {
  994.             get
  995.             {
  996.                 if (_polygonCollider == null)
  997.                     _polygonCollider = gameObject.GetComponent<PolygonCollider2D>();
  998.                 if (_polygonCollider == null)
  999.                     _polygonCollider = gameObject.AddComponent<PolygonCollider2D>();
  1000.                 return _polygonCollider;
  1001.             }
  1002.         }
  1003.         private PolygonCollider2D _polygonCollider;
  1004.         /// <summary>
  1005.         /// if it's true collider will be change in run time.
  1006.         /// </summary>
  1007.         public bool generateColliderInRunTime
  1008.         {
  1009.             get { return _generateColliderInRunTime; }
  1010.             set
  1011.             {
  1012.                 if (value != _generateColliderInRunTime)
  1013.                 {
  1014.                     _generateColliderInRunTime = value;
  1015.                     if (value == true)
  1016.                     {
  1017.                         dirty_collider = true;
  1018.                     }
  1019.                 }
  1020.             }
  1021.         }
  1022.         [SerializeField]
  1023.         private bool _generateColliderInRunTime = false;
  1024.         /// <summary>
  1025.         /// Generate PolygonCollider2d
  1026.         /// </summary>
  1027.         public void GenerateCollider()
  1028.         {
  1029.             polygonCollider.pathCount = borderPaths.Count;
  1030.             for (int i = 0; i < borderPaths.Count; i++)
  1031.             {
  1032.                 PolygonBorderPath colliderPath = borderPaths[i];
  1033.                 Vector2[] cPoints = new Vector2[colliderPath.points.Length];
  1034.                 for (int j = 0; j < colliderPath.points.Length; j++)
  1035.                 {
  1036.                     SpritePoint currentPoint = points[colliderPath.points[j]];
  1037.  
  1038.                     cPoints[j] = SpritePositionToLocal(GetSpritePositionOfSpritePoint(currentPoint) + currentPoint.colliderOffset);
  1039.                 }
  1040.                 polygonCollider.SetPath(i, cPoints);
  1041.             }
  1042.         }
  1043.         protected void OnBecameVisible()
  1044.         {
  1045.             if (Application.isPlaying) this.enabled = true;
  1046.         }
  1047.         void OnBecameInvisible()
  1048.         {
  1049.             if (Application.isPlaying) this.enabled = false;
  1050.         }
  1051.  
  1052.  
  1053.     }
  1054. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement