meatbag

UnityPaint converted to C#

Oct 28th, 2012
1,960
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. public class Uber : MonoBehaviour
  6. {
  7.  
  8. #region painter
  9. public Texture2D sourceBaseTex;
  10. private Texture2D baseTex;
  11.  
  12. void  Start ()
  13. {
  14.     baseTex = (Texture2D) Instantiate( sourceBaseTex );
  15. }
  16.  
  17.  
  18. private Vector2 dragStart;
  19. private Vector2 dragEnd;
  20. public enum Tool {
  21.     None,
  22.     Line,
  23.     Brush,
  24.     Eraser,
  25.     Vector
  26. }
  27. private int tool2 = 1;
  28. public Samples AntiAlias = Samples.Samples4;
  29. public Tool tool = Tool.Brush;
  30. public Texture[] toolimgs;
  31. public Texture2D colorCircle;
  32. public float lineWidth = 1;
  33. public float strokeWidth = 1;
  34. public Color col = Color.white;
  35. public Color col2 = Color.white;
  36. public GUISkin gskin;
  37. public LineTool lineTool = new LineTool();
  38. public BrushTool brush = new BrushTool();
  39. public EraserTool eraser = new EraserTool();
  40. public Stroke stroke = new Stroke();
  41. public int zoom = 1;
  42. BezierPoint[] BezierPoints;
  43. void  OnGUI (){
  44.     GUI.skin = gskin;
  45.    
  46.     GUILayout.BeginArea ( new Rect(5,5,100+baseTex.width*zoom,baseTex.height*zoom),"","Box");
  47.     GUILayout.BeginArea ( new Rect(0,0,100,baseTex.height*zoom));
  48.     tool2 = GUILayout.Toolbar(tool2,toolimgs,"Tool");
  49.  
  50. //  tool = System.Enum.Parse (Tool,tool2.ToString ());
  51.    
  52.     // FIXME: Defaults to brush tool, fix enum parse above.
  53.     tool = Tool.Brush;
  54.    
  55.    
  56.     GUILayout.Label ("Drawing Options");
  57.     GUILayout.Space (10);
  58.     switch (tool) {
  59.         case Tool.Line:
  60.             GUILayout.Label ("Size "+ Mathf.Round (lineTool.width*10)/10);
  61.             lineTool.width = GUILayout.HorizontalSlider (lineTool.width,0,40);
  62.             col = RGBCircle (col,"",colorCircle);
  63.             break;
  64.         case Tool.Brush:
  65.             GUILayout.Label ("Size "+ Mathf.Round (brush.width*10)/10);
  66.             brush.width = GUILayout.HorizontalSlider (brush.width,0,40);
  67.             GUILayout.Label ("Hardness " + Mathf.Round (brush.hardness*10)/10);
  68.             brush.hardness = GUILayout.HorizontalSlider (brush.hardness,0.1f,50);
  69.             col = RGBCircle (col,"",colorCircle);
  70.             break;
  71.         case Tool.Eraser:
  72.             GUILayout.Label ("Size "+ Mathf.Round (eraser.width*10)/10);
  73.             eraser.width = GUILayout.HorizontalSlider (eraser.width,0,50);
  74.             GUILayout.Label ("Hardness " + Mathf.Round (eraser.hardness*10)/10);
  75.             eraser.hardness = GUILayout.HorizontalSlider (eraser.hardness,1,50);
  76.             break;
  77.     }
  78.    
  79.     if (tool==Tool.Line) {
  80.         stroke.enabled = GUILayout.Toggle (stroke.enabled,"Stroke");
  81.         GUILayout.Label ("Stroke Width "+ Mathf.Round (stroke.width*10)/10);
  82.         stroke.width = GUILayout.HorizontalSlider (stroke.width,0,lineWidth);
  83.         GUILayout.Label ("Secondary Color");
  84.         col2 = RGBCircle (col2,"",colorCircle);
  85.     }
  86.    
  87.     GUILayout.EndArea ();
  88.     GUI.DrawTexture ( new Rect(100,0,baseTex.width*zoom,baseTex.height*zoom),baseTex);
  89.     GUILayout.EndArea ();
  90. }
  91. private Vector2 preDrag;
  92. void  Update (){
  93.     Rect imgRect = new Rect(5+100,5,baseTex.width*zoom,baseTex.height*zoom);
  94.     Vector2 mouse = Input.mousePosition;
  95.     mouse.y = Screen.height-mouse.y;
  96.    
  97.     if (Input.GetKeyDown ("t")) {
  98.         test ();
  99.     }
  100.     if (Input.GetKeyDown ("mouse 0")) {
  101.        
  102.         if (imgRect.Contains (mouse)) {
  103.             if (tool==Tool.Vector) {
  104.                 var m2 = mouse-new Vector2(imgRect.x,imgRect.y);
  105.                 m2.y = imgRect.height-m2.y;
  106.                 var bz = new ArrayList (BezierPoints);
  107.                 bz.Add (new BezierPoint (m2,m2-new Vector2(50,10),m2+new Vector2(50,10)));
  108.                 BezierPoints = (BezierPoint[]) bz.ToArray();
  109.                 DrawBezier (BezierPoints,lineTool.width,col,baseTex);
  110.             }
  111.            
  112.             dragStart = mouse - new Vector2 (imgRect.x,imgRect.y);
  113.             dragStart.y =imgRect.height-dragStart.y;
  114.             dragStart.x = Mathf.Round (dragStart.x/zoom);
  115.             dragStart.y = Mathf.Round (dragStart.y/zoom);
  116.             //LineStart (mouse - Vector2 (imgRect.x,imgRect.y));
  117.            
  118.             dragEnd = mouse - new Vector2 (imgRect.x,imgRect.y);
  119.             dragEnd.x = Mathf.Clamp (dragEnd.x,0,imgRect.width);
  120.             dragEnd.y = imgRect.height-Mathf.Clamp (dragEnd.y,0,imgRect.height);
  121.             dragEnd.x = Mathf.Round ( dragEnd.x/zoom);
  122.             dragEnd.y = Mathf.Round ( dragEnd.y/zoom);
  123.         } else {
  124.             dragStart=Vector3.zero;
  125.         }
  126.        
  127.     }
  128.     if (Input.GetKey ("mouse 0")) {
  129.         if (dragStart==Vector2.zero) {
  130.             return;
  131.         }
  132.         dragEnd = mouse - new Vector2 (imgRect.x,imgRect.y);
  133.         dragEnd.x = Mathf.Clamp (dragEnd.x,0,imgRect.width);
  134.         dragEnd.y = imgRect.height-Mathf.Clamp (dragEnd.y,0,imgRect.height);
  135.         dragEnd.x = Mathf.Round ( dragEnd.x/zoom);
  136.         dragEnd.y = Mathf.Round ( dragEnd.y/zoom);
  137.        
  138.         if (tool==Tool.Brush) {
  139.             Brush (dragEnd,preDrag);
  140.         }
  141.         if (tool==Tool.Eraser) {
  142.             Eraser (dragEnd,preDrag);
  143.         }
  144.        
  145.     }
  146.     if (Input.GetKeyUp ("mouse 0") && dragStart != Vector2.zero) {
  147.         if (tool==Tool.Line) {
  148.             dragEnd = mouse - new Vector2 (imgRect.x,imgRect.y);
  149.             dragEnd.x = Mathf.Clamp (dragEnd.x,0,imgRect.width);
  150.             dragEnd.y = imgRect.height-Mathf.Clamp (dragEnd.y,0,imgRect.height);
  151.             dragEnd.x = Mathf.Round ( dragEnd.x/zoom);
  152.             dragEnd.y = Mathf.Round ( dragEnd.y/zoom);
  153.             Debug.Log ("Draw Line");
  154.             NumSamples=AntiAlias;
  155.             if (stroke.enabled) {
  156.                 baseTex = DrawLine (dragStart,dragEnd,lineTool.width,col,baseTex,true,col2,stroke.width);
  157.             } else {
  158.                 baseTex = DrawLine (dragStart,dragEnd,lineTool.width,col,baseTex);
  159.             }
  160.         }
  161.         dragStart=Vector2.zero;
  162.         dragEnd=Vector2.zero;
  163.     }
  164.     preDrag = dragEnd;
  165. }
  166.  
  167. void  Brush ( Vector2 p1 ,  Vector2 p2  ){
  168.     NumSamples=AntiAlias;
  169.     if (p2 == Vector2.zero) {
  170.         p2 = p1;
  171.     }
  172.     PaintLine (p1,p2,brush.width,col,brush.hardness,baseTex);
  173.     baseTex.Apply ();
  174. }
  175.  
  176. void  Eraser ( Vector2 p1 ,  Vector2 p2  ){
  177.     NumSamples=AntiAlias;
  178.     if (p2 == Vector2.zero) {
  179.         p2 = p1;
  180.     }
  181.     PaintLine (p1,p2,eraser.width,Color.white,eraser.hardness,baseTex);
  182.     baseTex.Apply ();
  183. }
  184.  
  185. void  test (){
  186.     float startTime = Time.realtimeSinceStartup;
  187.     var w = 100;
  188.     var h = 100;
  189.     var p1 = new BezierPoint (new Vector2(10,0),new Vector2(5,20),new Vector2(20,0));
  190.     var p2 = new BezierPoint (new Vector2(50,10),new Vector2(40,20),new Vector2(60,-10));
  191.     var c = new BezierCurve (p1.main,p1.control2,p2.control1,p2.main);
  192.     p1.curve2=c;
  193.     p2.curve1=c;
  194.     Vector2 elapsedTime = new Vector2 ((Time.realtimeSinceStartup-startTime)*10,0);
  195.     float startTime2 = Time.realtimeSinceStartup;
  196.     for (var i=0;i<w*h;i++) {
  197.         IsNearBezier (new Vector2(Random.value*80,Random.value*30),p1,p2,10);
  198.     }
  199.    
  200.     Vector2 elapsedTime2 = new Vector2 ((Time.realtimeSinceStartup-startTime2)*10,0);
  201.     Debug.Log ("Drawing took " + elapsedTime.ToString () + "  "+ elapsedTime2.ToString ());
  202.    
  203. }
  204.  
  205. public class LineTool {
  206.     public float width = 1;
  207. }
  208. public class EraserTool {
  209.     public float width = 1;
  210.     public float hardness = 1;
  211. }
  212. public class BrushTool {
  213.     public float width = 1;
  214.     public float hardness = 0;
  215.     public float spacing = 10;
  216. }
  217. public class Stroke {
  218.     public bool enabled= false;
  219.     public float width = 1;
  220. }
  221.  
  222. #endregion
  223.  
  224. #region gui controls
  225. static Color RGBSlider ( Color c ,  string label  )
  226. {
  227.     GUI.color=c;
  228.     GUILayout.Label (label);
  229.     GUI.color=Color.red;
  230.     c.r = GUILayout.HorizontalSlider (c.r,0,1);
  231.     GUI.color=Color.green;
  232.     c.g = GUILayout.HorizontalSlider (c.g,0,1);
  233.     GUI.color=Color.blue;
  234.     c.b = GUILayout.HorizontalSlider (c.b,0,1);
  235.     GUI.color=Color.white;
  236.     return c;
  237. }
  238.  
  239. static Color  RGBCircle ( Color c ,  string label ,  Texture2D colorCircle  ){
  240.     var r = GUILayoutUtility.GetAspectRect (1);
  241.     r.height = r.width -= 15;
  242.     var r2 = new Rect(r.x + r.width +5,r.y,10,r.height);
  243.     var hsb = new HSBColor (c);//It is much easier to work with HSB colours in this case
  244.    
  245.    
  246.     var cp = new Vector2 (r.x+r.width/2,r.y+r.height/2);
  247.    
  248.     if (Input.GetMouseButton (0)) {
  249.         var InputVector= Vector2.zero;
  250.         InputVector.x = cp.x - Event.current.mousePosition.x;
  251.         InputVector.y = cp.y - Event.current.mousePosition.y;
  252.        
  253.         var hyp = Mathf.Sqrt( (InputVector.x * InputVector.x) + (InputVector.y * InputVector.y) );
  254.         if (hyp <= r.width/2 + 5) {
  255.             hyp = Mathf.Clamp (hyp,0,r.width/2);
  256.             float a = Vector3.Angle(new Vector3(-1,0,0), InputVector);
  257.            
  258.             if (InputVector.y<0) {
  259.                 a = 360 - a;
  260.             }
  261.            
  262.             hsb.h = a / 360;
  263.             hsb.s = hyp / (r.width/2);
  264.         }
  265.     }
  266.    
  267.     var hsb2 = new HSBColor (c);
  268.     hsb2.b = 1;
  269.     var c2 = hsb2.ToColor ();
  270.     GUI.color = c2;
  271.     hsb.b = GUI.VerticalSlider (r2,hsb.b,1.0f,0.0f,"BWSlider","verticalsliderthumb");
  272.    
  273.     GUI.color = Color.white * hsb.b;
  274.     GUI.color = new Color( GUI.color.r, GUI.color.g, GUI.color.b, 1);
  275.     GUI.Box (r,colorCircle,GUIStyle.none);
  276.    
  277.     var pos = (new Vector2 (Mathf.Cos (hsb.h*360*Mathf.Deg2Rad),-Mathf.Sin (hsb.h*360*Mathf.Deg2Rad))*r.width*hsb.s/2);
  278.    
  279.     GUI.color = c;
  280.     GUI.Box ( new Rect(pos.x-5+cp.x,pos.y-5+cp.y,10,10),"","ColorcirclePicker");
  281.     GUI.color = Color.white;
  282.    
  283.     c = hsb.ToColor ();
  284.     return c;
  285. }
  286. #endregion
  287.  
  288. #region drawing
  289.  
  290. public enum Samples {
  291.     None,
  292.     Samples2,
  293.     Samples4,
  294.     Samples8,
  295.     Samples16,
  296.     Samples32,
  297.     RotatedDisc
  298. }
  299.  
  300. static Samples NumSamples = Samples.Samples4;
  301.  
  302. static Texture2D  DrawLine ( Vector2 from ,  Vector2 to ,  float w ,  Color col ,  Texture2D tex  ){
  303.     return DrawLine (from,to,w,col,tex,false,Color.black,0);
  304. }
  305.  
  306. static Texture2D  DrawLine ( Vector2 from ,  Vector2 to ,  float w ,  Color col ,  Texture2D tex ,  bool stroke ,   Color strokeCol ,  float strokeWidth  ){
  307.     w = Mathf.Round (w);//It is important to round the numbers otherwise it will mess up with the texture width
  308.     strokeWidth = Mathf.Round (strokeWidth);
  309.    
  310.     var extent = w + strokeWidth;
  311.     var stY = Mathf.Clamp (Mathf.Min (from.y,to.y)-extent,0,tex.height);//This is the topmost Y value
  312.     var stX =  Mathf.Clamp (Mathf.Min (from.x,to.x)-extent,0,tex.width);
  313.     var endY = Mathf.Clamp (Mathf.Max (from.y,to.y)+extent,0,tex.height);
  314.     var endX = Mathf.Clamp (Mathf.Max (from.x,to.x)+extent,0,tex.width);//This is the rightmost Y value
  315.    
  316.     strokeWidth = strokeWidth/2;
  317.     var strokeInner = (w-strokeWidth)*(w-strokeWidth);
  318.     var strokeOuter = (w+strokeWidth)*(w+strokeWidth);
  319.     var strokeOuter2 = (w+strokeWidth+1)*(w+strokeWidth+1);
  320.     var sqrW = w*w;//It is much faster to calculate with squared values
  321.    
  322.     var lengthX = endX-stX;
  323.     var lengthY = endY-stY;
  324.     var start = new Vector2 (stX,stY);
  325.     Color[] pixels = tex.GetPixels((int)stX, (int)stY, (int)lengthX, (int)lengthY, 0);//Get all pixels
  326.    
  327.     for (int y=0;y<lengthY;y++)
  328.     {
  329.         for (int x=0;x<lengthX;x++)
  330.         {//Loop through the pixels
  331.             var p = new Vector2 (x,y) + start;
  332.             var center = p + new Vector2(0.5f,0.5f);
  333.             float dist = (center-NearestPointStrict(from,to,center)).sqrMagnitude;//The squared distance from the center of the pixels to the nearest point on the line
  334.             if (dist<=strokeOuter2)
  335.             {
  336.                 var samples = Sample (p);
  337.                 var c = Color.black;
  338.                 var pc = pixels[y*(int)lengthX+x];
  339.                 for (int i=0;i<samples.Length;i++) {//Loop through the samples
  340.                     dist = (samples[i]-NearestPointStrict(from,to,samples[i])).sqrMagnitude;//The squared distance from the sample to the line
  341.                     if (stroke) {
  342.                         if (dist<=strokeOuter && dist >= strokeInner) {
  343.                             c+=strokeCol;
  344.                         } else if (dist<sqrW) {
  345.                             c+=col;
  346.                         } else {
  347.                             c+=pc;
  348.                         }
  349.                     } else {
  350.                         if (dist<sqrW) {//Is the distance smaller than the width of the line
  351.                             c+=col;
  352.                         } else {
  353.                             c+=pc;//No it wasn't, set it to be the original colour
  354.                         }
  355.                     }
  356.                 }
  357.                 c /= samples.Length;//Get the avarage colour
  358.                 pixels[y * (int)lengthX + x] = c;
  359.             }
  360.         }
  361.     }
  362.     tex.SetPixels((int)stX, (int)stY, (int)lengthX, (int)lengthY, pixels, 0);
  363.     tex.Apply ();
  364.     return tex;
  365. }
  366.  
  367. static Texture2D  Paint ( Vector2 pos ,  float rad ,  Color col ,  float hardness ,  Texture2D tex  ){
  368.     var start = new Vector2 (Mathf.Clamp (pos.x-rad,0,tex.width),Mathf.Clamp (pos.y-rad,0,tex.height));
  369.     var width = rad*2;
  370.     var end = new Vector2 (Mathf.Clamp (pos.x+rad,0,tex.width),Mathf.Clamp (pos.y+rad,0,tex.height));
  371.     var widthX = Mathf.Round (end.x-start.x);
  372.     var widthY = Mathf.Round (end.y-start.y);
  373.     var sqrRad = rad*rad;
  374.     var sqrRad2 = (rad+1)*(rad+1);
  375.     Color[] pixels = tex.GetPixels((int)start.x, (int)start.y, (int)widthX, (int)widthY, 0);
  376.    
  377.     for (var y=0;y<widthY;y++)
  378.     {
  379.         for (var x=0;x<widthX;x++)
  380.         {
  381.             var p = new Vector2 (x,y) + start;
  382.             var center = p + new Vector2(0.5f,0.5f);
  383.             float dist = (center-pos).sqrMagnitude;
  384.             if (dist>sqrRad2) {
  385.                 continue;
  386.             }
  387.             var samples = Sample (p);
  388.             var c = Color.black;
  389.             for (var i=0;i<samples.Length;i++)
  390.             {
  391.                 dist = GaussFalloff (Vector2.Distance(samples[i],pos),rad) * hardness;
  392.                 if (dist>0)
  393.                 {
  394.                     c += Color.Lerp (pixels[y*(int)widthX+x],col,dist);
  395.                 }
  396.                 else
  397.                 {
  398.                     c+=pixels[y*(int)widthX+x];
  399.                 }
  400.             }
  401.             c /= samples.Length;
  402.            
  403.             pixels[y*(int)widthX+x]=c;
  404.         }
  405.     }
  406.  
  407.     tex.SetPixels((int)start.x, (int)start.y, (int)widthX, (int)widthY, pixels, 0);
  408.     return tex;
  409. }
  410.  
  411. static Texture2D  PaintLine ( Vector2 from ,  Vector2 to ,  float rad ,  Color col ,  float hardness ,  Texture2D tex  )
  412. {
  413.     var width = rad*2;
  414.  
  415.     var extent = rad;
  416.     var stY = Mathf.Clamp(Mathf.Min(from.y, to.y) - extent, 0, tex.height);
  417.     var stX = Mathf.Clamp(Mathf.Min(from.x, to.x) - extent, 0, tex.width);
  418.     var endY = Mathf.Clamp(Mathf.Max(from.y, to.y) + extent, 0, tex.height);
  419.     var endX = Mathf.Clamp(Mathf.Max(from.x, to.x) + extent, 0, tex.width);
  420.  
  421.     var lengthX = endX - stX;
  422.     var lengthY = endY - stY;
  423.  
  424.     var sqrRad = rad * rad;
  425.     var sqrRad2 = (rad + 1) * (rad + 1);
  426.     Color[] pixels = tex.GetPixels((int)stX, (int)stY, (int)lengthX, (int)lengthY, 0);
  427.     var start = new Vector2(stX, stY);
  428.     //Debug.Log (widthX + "   "+ widthY + "   "+ widthX*widthY);
  429.     for (int y=0;y<(int)lengthY;y++)
  430.     {
  431.         for (int x=0;x<(int)lengthX;x++)
  432.         {
  433.             var p = new Vector2 (x,y) + start;
  434.             var center = p + new Vector2(0.5f, 0.5f);
  435.             float dist = (center-NearestPointStrict(from,to,center)).sqrMagnitude;
  436.             if (dist>sqrRad2) {
  437.                 continue;
  438.             }
  439.             dist = GaussFalloff (Mathf.Sqrt(dist),rad) * hardness;
  440.             //dist = (samples[i]-pos).sqrMagnitude;
  441.             Color c;
  442.             if (dist>0) {
  443.                 c = Color.Lerp(pixels[y * (int)lengthX + x], col, dist);
  444.             } else {
  445.                 c = pixels[y * (int)lengthX + x];
  446.             }
  447.  
  448.             pixels[y * (int)lengthX + x] = c;
  449.         }
  450.     }
  451.     tex.SetPixels((int)start.x, (int)start.y, (int)lengthX, (int)lengthY, pixels, 0);
  452.     return tex;
  453. }
  454.  
  455. internal class BezierPoint
  456. {
  457.     internal Vector2 main;
  458.     internal Vector2 control1;//Think of as left
  459.     internal Vector2 control2;//Right
  460.     //Rect rect;
  461.     internal BezierCurve curve1;//Left
  462.     internal BezierCurve curve2;//Right
  463.    
  464.     internal BezierPoint ( Vector2 m ,  Vector2 l ,  Vector2 r  ){
  465.         main = m;
  466.         control1 = l;
  467.         control2 = r;
  468.     }
  469. }
  470.  
  471. internal class BezierCurve {
  472.     internal Vector2[] points;
  473.     internal float aproxLength;
  474.     internal Rect rect;
  475.     internal Vector2  Get ( float t  )
  476.     {
  477.         int t2 = (int) Mathf.Round (t*(points.Length-1));
  478.         return points[t2];
  479.     }
  480.  
  481.     void  Init ( Vector2 p0 ,  Vector2 p1 ,  Vector2 p2 ,  Vector2 p3  )
  482.     {
  483.        
  484.         Vector2 topleft = new Vector2(Mathf.Infinity,Mathf.Infinity);
  485.         Vector2 bottomright = new Vector2(Mathf.NegativeInfinity,Mathf.NegativeInfinity);
  486.        
  487.         topleft.x = Mathf.Min (topleft.x,p0.x);
  488.         topleft.x = Mathf.Min (topleft.x,p1.x);
  489.         topleft.x = Mathf.Min (topleft.x,p2.x);
  490.         topleft.x = Mathf.Min (topleft.x,p3.x);
  491.        
  492.         topleft.y = Mathf.Min (topleft.y,p0.y);
  493.         topleft.y = Mathf.Min (topleft.y,p1.y);
  494.         topleft.y = Mathf.Min (topleft.y,p2.y);
  495.         topleft.y = Mathf.Min (topleft.y,p3.y);
  496.        
  497.         bottomright.x = Mathf.Max (bottomright.x,p0.x);
  498.         bottomright.x = Mathf.Max (bottomright.x,p1.x);
  499.         bottomright.x = Mathf.Max (bottomright.x,p2.x);
  500.         bottomright.x = Mathf.Max (bottomright.x,p3.x);
  501.        
  502.         bottomright.y = Mathf.Max (bottomright.y,p0.y);
  503.         bottomright.y = Mathf.Max (bottomright.y,p1.y);
  504.         bottomright.y = Mathf.Max (bottomright.y,p2.y);
  505.         bottomright.y = Mathf.Max (bottomright.y,p3.y);
  506.        
  507.         rect = new Rect(topleft.x,topleft.y,bottomright.x-topleft.x,bottomright.y-topleft.y);
  508.        
  509.        
  510.         var ps = new List<Vector2>();
  511.        
  512.         var point1  = CubicBezier (0,p0,p1,p2,p3);
  513.         var point2  = CubicBezier (0.05f,p0,p1,p2,p3);
  514.         var point3  = CubicBezier (0.1f,p0,p1,p2,p3);
  515.         var point4  = CubicBezier (0.15f,p0,p1,p2,p3);
  516.        
  517.         var point5  = CubicBezier (0.5f,p0,p1,p2,p3);
  518.         var point6  = CubicBezier (0.55f,p0,p1,p2,p3);
  519.         var point7  = CubicBezier (0.6f,p0,p1,p2,p3);
  520.        
  521.         aproxLength = Vector2.Distance(point1,point2) + Vector2.Distance (point2,point3) + Vector2.Distance (point3,point4)  + Vector2.Distance (point5,point6)  + Vector2.Distance (point6,point7);
  522.        
  523.         Debug.Log (Vector2.Distance(point1,point2) + "     " + Vector2.Distance(point3,point4) + "   " + Vector2.Distance(point6, point7));
  524.         aproxLength*= 4;
  525.        
  526.         float a2 = 0.5f/aproxLength;//Double the amount of points since the approximation is quite bad
  527.         for (float i = 0 ;i<1;i+=a2)
  528.         {
  529.             ps.Add (CubicBezier (i,p0,p1,p2,p3));
  530.         }
  531.        
  532.         points = ps.ToArray();
  533.     }
  534.    
  535.      internal BezierCurve ( Vector2 main ,  Vector2 control1 ,  Vector2 control2 ,  Vector2 end  )
  536.      {
  537.         Init (main,control1,control2,end);
  538.     }
  539. }
  540.  
  541. static void  DrawBezier ( BezierPoint[] points ,  float rad ,  Color col ,  Texture2D tex  )
  542. {
  543.     rad = Mathf.Round (rad);//It is important to round the numbers otherwise it will mess up with the texture width
  544.    
  545.     if (points.Length<=1)
  546.         return;
  547.    
  548.     Vector2 topleft = new Vector2(Mathf.Infinity,Mathf.Infinity);
  549.     Vector2 bottomright = new Vector2(0,0);
  550.    
  551.     for (int i=0;i<points.Length-1;i++)
  552.     {
  553.         Vector2 main = points[i].main;
  554.         Vector2 control2 = points[i].control2;
  555.         Vector2 control1 = points[i + 1].control1;
  556.         Vector2 main2 = points[i + 1].main;
  557.         BezierCurve curve = new BezierCurve( main, control2, control1, main2 );
  558.         points[i].curve2 = curve;
  559.         points[i+1].curve1 = curve;
  560.        
  561.         topleft.x = Mathf.Min (topleft.x,curve.rect.x);
  562.    
  563.         topleft.y = Mathf.Min (topleft.y,curve.rect.y);
  564.    
  565.         bottomright.x = Mathf.Max (bottomright.x,curve.rect.x+curve.rect.width);
  566.    
  567.         bottomright.y = Mathf.Max (bottomright.y,curve.rect.y+curve.rect.height);
  568.     }
  569.    
  570.     topleft-= new Vector2(rad,rad);
  571.     bottomright+= new Vector2(rad,rad);
  572.    
  573.     var start = new Vector2 (Mathf.Clamp (topleft.x,0,tex.width),Mathf.Clamp (topleft.y,0,tex.height));
  574.     var width = new Vector2(Mathf.Clamp(bottomright.x - topleft.x, 0, tex.width - start.x), Mathf.Clamp(bottomright.y - topleft.y, 0, tex.height - start.y));
  575.  
  576.     Color[] pixels = tex.GetPixels((int)start.x, (int)start.y, (int)width.x, (int)width.y, 0);
  577.    
  578.     for (var y=0;y<width.y;y++)
  579.     {
  580.         for (var x = 0; x < width.x; x++)
  581.         {
  582.             var p = new Vector2(x+start.x,y+start.y);
  583.             if (!IsNearBeziers (p,points,rad+2))
  584.             {
  585.                 continue;
  586.             }
  587.            
  588.             var samples = Sample (p);
  589.             var c = Color.black;
  590.             var pc = pixels[y*(int)width.x+x];//Previous pixel color
  591.             for (var i=0;i<samples.Length;i++)
  592.             {
  593.                 if (IsNearBeziers (samples[i],points,rad))
  594.                 {
  595.                     c+= col;
  596.                 } else {
  597.                     c+= pc;
  598.                 }
  599.             }
  600.            
  601.             c /= samples.Length;
  602.            
  603.             pixels[y*(int)width.x+x] = c;
  604.         }
  605.     }
  606.  
  607.     tex.SetPixels((int)start.x, (int)start.y, (int)width.x, (int)width.y, pixels, 0);
  608.     tex.Apply ();
  609. }
  610.  
  611. static void AddP(List<Vector2> tmpList, Vector2 p, float ix, float iy )
  612. {
  613.     var x = p.x + ix;
  614.     var y = p.y + iy;
  615.     tmpList.Add(new Vector2(x, y));
  616. }
  617.  
  618. static Vector2[] Sample ( Vector2 p  )
  619. {
  620.     List<Vector2> tmpList = new List<Vector2>(32);
  621.  
  622.     switch (NumSamples)
  623.     {
  624.         case Samples.None:
  625.             AddP(tmpList,p,0.5f,0.5f);
  626.             break;
  627.  
  628.         case Samples.Samples2:
  629.             AddP(tmpList,p,0.25f,0.5f);
  630.             AddP(tmpList,p,0.75f,0.5f);
  631.             break;
  632.  
  633.         case Samples.Samples4:
  634.             AddP(tmpList,p,0.25f,0.5f);
  635.             AddP(tmpList,p,0.75f,0.5f);
  636.             AddP(tmpList,p,0.5f,0.25f);
  637.             AddP(tmpList,p,0.5f,0.75f);
  638.             break;
  639.  
  640.         case Samples.Samples8:
  641.             AddP(tmpList,p,0.25f,0.5f);
  642.             AddP(tmpList,p,0.75f,0.5f);
  643.             AddP(tmpList,p,0.5f,0.25f);
  644.             AddP(tmpList,p,0.5f,0.75f);
  645.  
  646.             AddP(tmpList,p,0.25f,0.25f);
  647.             AddP(tmpList,p,0.75f,0.25f);
  648.             AddP(tmpList,p,0.25f,0.75f);
  649.             AddP(tmpList,p,0.75f,0.75f);
  650.             break;
  651.         case Samples.Samples16:    
  652.             AddP(tmpList,p,0,0);
  653.             AddP(tmpList,p,0.3f,0);
  654.             AddP(tmpList,p,0.7f,0);
  655.             AddP(tmpList,p,1,0);
  656.  
  657.             AddP(tmpList,p,0,0.3f);
  658.             AddP(tmpList,p,0.3f,0.3f);
  659.             AddP(tmpList,p,0.7f,0.3f);
  660.             AddP(tmpList,p,1,0.3f);
  661.  
  662.             AddP(tmpList,p,0,0.7f);
  663.             AddP(tmpList,p,0.3f,0.7f);
  664.             AddP(tmpList,p,0.7f,0.7f);
  665.             AddP(tmpList,p,1,0.7f);
  666.  
  667.             AddP(tmpList,p,0,1);
  668.             AddP(tmpList,p,0.3f,1);
  669.             AddP(tmpList,p,0.7f,1);
  670.             AddP(tmpList,p,1,1);
  671.             break;
  672.  
  673.         case Samples.Samples32:
  674.             AddP(tmpList,p,0,0);
  675.             AddP(tmpList,p,1,0);
  676.             AddP(tmpList,p,0,1);
  677.             AddP(tmpList,p,1,1);
  678.  
  679.             AddP(tmpList,p,0.2f,0.2f);
  680.             AddP(tmpList,p,0.4f,0.2f);
  681.             AddP(tmpList,p,0.6f,0.2f);
  682.             AddP(tmpList,p,0.8f,0.2f);
  683.  
  684.             AddP(tmpList,p,0.2f,0.4f);
  685.             AddP(tmpList,p,0.4f,0.4f);
  686.             AddP(tmpList,p,0.6f,0.4f);
  687.             AddP(tmpList,p,0.8f,0.4f);
  688.  
  689.             AddP(tmpList,p,0.2f,0.6f);
  690.             AddP(tmpList,p,0.4f,0.6f);
  691.             AddP(tmpList,p,0.6f,0.6f);
  692.             AddP(tmpList,p,0.8f,0.6f);
  693.  
  694.             AddP(tmpList,p,0.2f,0.8f);
  695.             AddP(tmpList,p,0.4f,0.8f);
  696.             AddP(tmpList,p,0.6f,0.8f);
  697.             AddP(tmpList,p,0.8f,0.8f);
  698.  
  699.             AddP(tmpList,p,0.5f,0);
  700.             AddP(tmpList,p,0.5f,1);
  701.             AddP(tmpList,p,0,0.5f);
  702.             AddP(tmpList,p,1,0.5f);
  703.            
  704.             AddP(tmpList,p,0.5f,0.5f);
  705.             break;
  706.         case Samples.RotatedDisc:
  707.             AddP(tmpList,p,0,0);
  708.             AddP(tmpList,p,1,0);
  709.             AddP(tmpList,p,0,1);
  710.             AddP(tmpList,p,1,1);
  711.  
  712.             Vector2 pq = new Vector2(p.x + 0.5f, p.y + 0.5f);
  713.             AddP(tmpList,pq,0.258f,0.965f);//Sin (75°) && Cos (75°)
  714.             AddP(tmpList,pq,-0.965f,-0.258f);
  715.             AddP(tmpList,pq,0.965f,0.258f);
  716.             AddP(tmpList,pq,0.258f,-0.965f);
  717.             break;
  718.     }
  719.  
  720.     return tmpList.ToArray();
  721. }
  722.  
  723. #endregion
  724.  
  725. #region mathfx
  726.  
  727. static float Hermite ( float start ,   float end ,   float value  ){
  728.     return Mathf.Lerp(start, end, value * value * (3.0f - 2.0f * value));
  729. }
  730.    
  731. static float Sinerp ( float start ,   float end ,   float value  ){
  732.     return Mathf.Lerp(start, end, Mathf.Sin(value * Mathf.PI * 0.5f));
  733. }
  734.  
  735. static float Coserp ( float start ,   float end ,   float value  ){
  736.     return Mathf.Lerp(start, end, 1.0f - Mathf.Cos(value * Mathf.PI * 0.5f));
  737. }
  738.  
  739. static float Berp ( float start ,   float end ,   float value  ){
  740.     value = Mathf.Clamp01(value);
  741.     value = (Mathf.Sin(value * Mathf.PI * (0.2f + 2.5f * value * value * value)) * Mathf.Pow(1 - value, 2.2f) + value) * (1 + (1.2f * (1 - value)));
  742.     return start + (end - start) * value;
  743. }
  744.    
  745. static float SmoothStep ( float x ,   float min ,   float max  ){
  746.     x = Mathf.Clamp (x, min, max);
  747.     var v1= (x-min)/(max-min);
  748.     var v2= (x-min)/(max-min);
  749.     return -2*v1 * v1 *v1 + 3*v2 * v2;
  750. }
  751.  
  752. static float Lerp ( float start ,   float end ,   float value  ){
  753.     return ((1.0f - value) * start) + (value * end);
  754. }
  755.  
  756. static Vector3 NearestPoint ( Vector3 lineStart ,   Vector3 lineEnd ,   Vector3 point  ){
  757.     var lineDirection= Vector3.Normalize(lineEnd-lineStart);
  758.     var closestPoint= Vector3.Dot((point-lineStart),lineDirection)/Vector3.Dot(lineDirection,lineDirection);
  759.     return lineStart+(closestPoint*lineDirection);
  760. }
  761.  
  762. static Vector3 NearestPointStrict ( Vector3 lineStart ,   Vector3 lineEnd ,   Vector3 point  ){
  763.     var fullDirection= lineEnd-lineStart;
  764.     var lineDirection= Vector3.Normalize(fullDirection);
  765.     var closestPoint= Vector3.Dot((point-lineStart),lineDirection)/Vector3.Dot(lineDirection,lineDirection);
  766.     return lineStart+(Mathf.Clamp(closestPoint,0.0f,Vector3.Magnitude(fullDirection))*lineDirection);
  767. }
  768.  
  769. static Vector2 NearestPointStrict ( Vector2 lineStart ,   Vector2 lineEnd ,   Vector2 point  ){
  770.     var fullDirection= lineEnd-lineStart;
  771.     var lineDirection= Normalize(fullDirection);
  772.     var closestPoint= Vector2.Dot((point-lineStart),lineDirection)/Vector2.Dot(lineDirection,lineDirection);
  773.     return lineStart+(Mathf.Clamp(closestPoint,0.0f,fullDirection.magnitude)*lineDirection);
  774. }
  775.  
  776.  
  777.  
  778. static float Bounce ( float x  ){
  779.     return Mathf.Abs(Mathf.Sin(6.28f*(x+1)*(x+1)) * (1-x));
  780. }
  781.    
  782. // test for value that is near specified float (due to floating point inprecision)
  783. // all thanks to Opless for this!
  784. static bool Approx ( float val ,   float about ,   float range  ){
  785.      return ( ( Mathf.Abs(val - about) < range) );
  786. }
  787.  
  788. // test if a Vector3 is close to another Vector3 (due to floating point inprecision)
  789. // compares the square of the distance to the square of the range as this
  790. // avoids calculating a square root which is much slower than squaring the range
  791. static bool Approx ( Vector3 val ,   Vector3 about ,   float range  ){
  792.     return ( (val - about).sqrMagnitude < range*range);
  793. }
  794. static float GaussFalloff ( float distance  ,   float inRadius  ){
  795.     return Mathf.Clamp01 (Mathf.Pow (360.0f, -Mathf.Pow (distance / inRadius, 2.5f) - 0.01f));
  796. }
  797. // CLerp - Circular Lerp - is like lerp but handles the wraparound from 0 to 360.
  798. // This is useful when interpolating eulerAngles and the object
  799. // crosses the 0/360 boundary.  The standard Lerp function causes the object
  800. // to rotate in the wrong direction and looks stupid. Clerp fixes that.
  801. static float Clerp ( float start ,   float end ,   float value  ){
  802.    var min= 0.0f;
  803.    var max = 360.0f;
  804.    var half = Mathf.Abs((max - min) / 2.0f);//half the distance between min and max
  805.    var retval = 0.0f;
  806.    var diff = 0.0f;
  807.    
  808.    if((end - start) < -half){
  809.        diff = ((max - start)+end)*value;
  810.        retval =  start+diff;
  811.    }
  812.    else if((end - start) > half){
  813.        diff = -((max - end)+start)*value;
  814.        retval =  start+diff;
  815.    }
  816.    else retval =  start+(end-start)*value;
  817.    
  818.    return retval;
  819. }
  820.  
  821.  
  822. //======= NEW =========//
  823.  
  824.  
  825. static Vector2 RotateVector(Vector2 vector, float rad)
  826. {
  827.     rad *= Mathf.Deg2Rad;
  828.     var res = new Vector2 ((vector.x * Mathf.Cos(rad)) - (vector.y * Mathf.Sin(rad)),(vector.x * Mathf.Sin(rad)) + (vector.y * Mathf.Cos(rad)));
  829.     return res;
  830. }
  831.  
  832. static Vector2  IntersectPoint ( Vector2 start1 ,  Vector2 start2 ,  Vector2 dir1 ,  Vector2 dir2  ){
  833.     if (dir1.x==dir2.x) {
  834.         return Vector2.zero;
  835.     }
  836.    
  837.     var h1 = dir1.y/dir1.x;
  838.     var h2 = dir2.y / dir2.x;
  839.    
  840.     if (h1==h2)
  841.     {
  842.         return Vector2.zero;
  843.     }
  844.    
  845.     var line1 = new Vector2 (h1,start1.y-start1.x*h1);
  846.     var line2 = new Vector2 (h2,start2.y-start2.x*h2);
  847.    
  848.     var y1 = line2.y-line1.y;
  849.     var x1 = line1.x-line2.x;
  850.    
  851.     var x2 = y1 / x1;
  852.    
  853.     var y2 = line1.x*x2 + line1.y;
  854.     return new Vector2(x2,y2);
  855. }
  856.  
  857. static Vector2 ThreePointCircle ( Vector2 a1 ,  Vector2 a2 ,  Vector2 a3  )
  858. {
  859.     var dir = a2-a1;
  860.     dir /= 2;
  861.     var b1 = a1+dir;
  862.     dir = RotateVector (dir,90);
  863.     var l1 = dir;
  864.    
  865.     dir = a3-a2;
  866.     dir /= 2;
  867.     var b2 = a2 + dir;
  868.     dir = RotateVector (dir,90);
  869.     var l2 = dir;
  870.     var p = IntersectPoint(b1, b2, l1, l2);
  871.     return p;
  872. }
  873.  
  874. //===== Bezier ====== //
  875.  
  876. static Vector2  CubicBezier ( float t ,  Vector2 p0 ,  Vector2 p1 ,  Vector2 p2 ,  Vector2 p3  )
  877. {
  878.     // FIXME: fix bezier curve algorithm.
  879. /*  t = Mathf.Clamp01 (t);
  880.     var t2 = 1-t;
  881.     return Mathf.Pow(t2, 3) * p0 + 3 * Mathf.Pow(t2, 2) * t * p1 + 3 * t2 * Mathf.Pow(t, 2) * p2 + Mathf.Pow(t, 3) * p3;
  882.  */
  883.     return Vector2.zero;
  884. }
  885.  
  886. static Vector2 NearestPointOnBezier(Vector2 p, BezierCurve c, float accuracy, bool doubleAc)
  887. {
  888.      float minDist = Mathf.Infinity;
  889.     float minT = 0;
  890.     Vector2 minP = Vector2.zero;
  891.     for (float i = 0 ;i<1;i+=accuracy)
  892.     {
  893.         var point  = c.Get (i);
  894.         float d = (p - point).sqrMagnitude;
  895.         if (d<minDist) {
  896.             minDist=d;
  897.             minT = i;
  898.             minP = point;
  899.         }
  900.     }
  901.    
  902.     if (!doubleAc)
  903.     {
  904.         return minP;
  905.     }
  906.  
  907.     float st = Mathf.Clamp01(minT - accuracy);
  908.     float en = Mathf.Clamp01 (minT+accuracy);
  909.    
  910.    
  911.     for (var i=st;i<en;i+=accuracy/10)
  912.     {
  913.         var point  = c.Get (i);
  914.         float d= (p - point).sqrMagnitude;
  915.         if (d<minDist)
  916.         {
  917.             minDist=d;
  918.             minT = i;
  919.             minP = point;
  920.         }
  921.     }
  922.    
  923.     return minP;
  924. }
  925.  
  926. static bool IsNearBezierTest ( Vector2 p ,  BezierCurve c ,  float accuracy ,  float maxDist  ){
  927.     Vector2 prepoint = c.Get (0);
  928.     for (float i = accuracy;i<1;i+=accuracy)
  929.     {
  930.         var point  = c.Get (i);
  931.         float d = (p - point).sqrMagnitude;
  932.         float d2 = (prepoint - point + new Vector2(maxDist,maxDist)).sqrMagnitude;
  933.         if (d<=d2*2)
  934.             return true;
  935.     }
  936.    
  937.     return false;
  938. }
  939.  
  940. static Vector2  NearestPointOnBezier ( Vector2 p ,  Vector2 p0 ,  Vector2 p1 ,  Vector2 p2 ,  Vector2 p3  )
  941. {
  942.     float minDist = Mathf.Infinity;
  943.     float minT = 0;
  944.     Vector2 minP = Vector2.zero;
  945.     for (float i = 0 ;i<1;i+=0.01f)
  946.     {
  947.         var point  = CubicBezier (i,p0,p1,p2,p3);
  948.         float d = (p - point).sqrMagnitude;
  949.         if (d<minDist) {
  950.             minDist=d;
  951.             minT = i;
  952.             minP = point;
  953.         }
  954.     }
  955.    
  956.     float st = Mathf.Clamp01 (minT-0.01f);
  957.     float en = Mathf.Clamp01(minT + 0.01f);
  958.    
  959.     for (var i=st;i<en;i+=0.001f)
  960.     {
  961.         var point  = CubicBezier (i,p0,p1,p2,p3);
  962.         var d= (p - point).sqrMagnitude;
  963.         if (d<minDist)
  964.         {
  965.             minDist=d;
  966.             minT = i;
  967.             minP = point;
  968.         }
  969.     }
  970.    
  971.     return minP;
  972.    
  973. }
  974.  
  975. static bool  IsNearBezier ( Vector2 p ,  BezierPoint point1 ,  BezierPoint point2 ,  float rad  )
  976. {
  977.     if (point1.curve2 != point2.curve1) {
  978.         Debug.LogError ("Curves Not The Same");
  979.         return false;
  980.     }
  981.    
  982.     BezierCurve curve = point1.curve2;
  983.    
  984.     var r = curve.rect;
  985.     r.x-=rad;
  986.     r.y-=rad;
  987.     r.width+=rad*2;
  988.     r.height+=rad*2;
  989.    
  990.     if (!r.Contains (p)) {
  991.         return false;
  992.     }
  993.    
  994.     var nearest = NearestPointOnBezier (p,curve,0.1f,false);
  995.    
  996.     var sec = point1.curve2.aproxLength/10;
  997.    
  998.     if ((nearest-p).sqrMagnitude>=(sec*3)*(sec*3)) {
  999.         return false;
  1000.     }
  1001.    
  1002.     nearest = NearestPointOnBezier (p,curve,0.01f,true);
  1003.    
  1004.     if ((nearest-p).sqrMagnitude<=rad*rad) {
  1005.         return true;
  1006.     }
  1007.    
  1008.     return false;
  1009. }
  1010.  
  1011. static bool  IsNearBeziers ( Vector2 p ,  BezierPoint[] points ,  float rad  )
  1012. {
  1013.     for (var i=0;i<points.Length-1;i++)
  1014.     {
  1015.         if (IsNearBezier (p,points[i],points[i+1],rad))
  1016.         {
  1017.             return true;
  1018.         }
  1019.     }
  1020.     return false;
  1021. }
  1022.  
  1023. //====== End Bezier ========//
  1024.  
  1025. static Vector2  NearestPointOnCircle ( Vector2 p ,  Vector2 center ,  float w  )
  1026. {
  1027.     Vector2 dir = p-center;
  1028.     dir = Normalize (dir);
  1029.     dir *= w;
  1030.     return center+dir;
  1031. }
  1032. static Vector2 Normalize(Vector2 p)
  1033. {
  1034.     float mag = p.magnitude;
  1035.     return p/mag;
  1036. }
  1037.  
  1038. #endregion
  1039.  
  1040. };
RAW Paste Data