325 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C#
		
	
	
	
 | 
						|
using Godot;
 | 
						|
using Rokojori;
 | 
						|
using System.Collections.Generic;
 | 
						|
 | 
						|
namespace Rokojori
 | 
						|
{  
 | 
						|
  public enum SplineAutoOrientationMode
 | 
						|
  {
 | 
						|
    Tangent,
 | 
						|
    Next_Neighbor
 | 
						|
  }
 | 
						|
 | 
						|
  [Tool]
 | 
						|
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Spline.svg") ]
 | 
						|
  public partial class Spline : Node3D
 | 
						|
#if TOOLS 
 | 
						|
 , GizmoDrawer
 | 
						|
#endif
 | 
						|
 | 
						|
  { 
 | 
						|
 | 
						|
    public static Spline Create( Node parent, List<Vector3> points, bool closed = false )
 | 
						|
    {
 | 
						|
      var spline = parent.CreateChild<Spline>();
 | 
						|
 | 
						|
      spline.closed = closed;
 | 
						|
      spline.autoOrienation = true;
 | 
						|
 | 
						|
      points.ForEach(
 | 
						|
        ( p )=>
 | 
						|
        {
 | 
						|
          var sp = spline.CreateChild<SplinePoint>();
 | 
						|
          sp.GlobalPosition = p;
 | 
						|
        }
 | 
						|
      );
 | 
						|
 | 
						|
      return spline;
 | 
						|
    }
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public bool closed = false;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public int editorResolution = 20;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public bool autoOrienation = false;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public SplineAutoOrientationMode autoOrientationMode = SplineAutoOrientationMode.Tangent;
 | 
						|
 | 
						|
    [Export( PropertyHint.Range, "-1,1")]
 | 
						|
    public float autoOrientationTangentAdjustment = 0f;
 | 
						|
 | 
						|
    [Export]  
 | 
						|
    public Vector3 autoOrientationUp = Vector3.Up;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public bool updateAlways = false;
 | 
						|
 | 
						|
    [Export]
 | 
						|
    public int xzPathBakeResolution = 50;
 | 
						|
 | 
						|
 | 
						|
    public void SetEditorPointSize( float size )
 | 
						|
    {
 | 
						|
      this.ForEachDirectChild<SplinePoint>( p => p.editorSplinePointSize = size );
 | 
						|
    }
 | 
						|
 | 
						|
    SplineCurve splineCurve;
 | 
						|
    Vector3 min;
 | 
						|
    Vector3 max;
 | 
						|
 | 
						|
    public Box3 GetBounds()
 | 
						|
    {
 | 
						|
      GetCurve();
 | 
						|
 | 
						|
      return Box3.Create( min, max );
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public SplineCurve GetCurve()
 | 
						|
    {
 | 
						|
      if ( splineCurve == null )
 | 
						|
      {
 | 
						|
        var splinePoints = Nodes.GetDirectChildren<SplinePoint>( this );      
 | 
						|
 | 
						|
        splineCurve = new SplineCurveCreator().Create( splinePoints, closed );
 | 
						|
 | 
						|
        min = splineCurve.MinPointPosition();
 | 
						|
        max = splineCurve.MaxPointPosition();
 | 
						|
      }
 | 
						|
 | 
						|
      return splineCurve;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    
 | 
						|
 | 
						|
    SplineCurve splineCurveXZ;
 | 
						|
 | 
						|
    public SplineCurve GetCurveXZ()
 | 
						|
    {
 | 
						|
      if ( splineCurveXZ == null )
 | 
						|
      {
 | 
						|
        var splinePoints = Nodes.GetDirectChildren<SplinePoint>( this );
 | 
						|
 | 
						|
        splineCurveXZ = new SplineCurveCreator().Create( splinePoints, closed ).CloneForXZ( 0 );
 | 
						|
      }
 | 
						|
 | 
						|
      return splineCurveXZ;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    Path2 xzPath;
 | 
						|
    Convex2Group convex2Group;
 | 
						|
 | 
						|
    public Path2 GetXZPath2()
 | 
						|
    {
 | 
						|
      if ( xzPath == null )
 | 
						|
      {
 | 
						|
        xzPath = Path2.AsXZFrom( GetCurve(), closed, xzPathBakeResolution );
 | 
						|
      }
 | 
						|
 | 
						|
      return xzPath;
 | 
						|
    }
 | 
						|
 | 
						|
    public Convex2Group GetConvex2Group()
 | 
						|
    {
 | 
						|
      if ( convex2Group == null )
 | 
						|
      {
 | 
						|
        convex2Group = Convex2Group.FromPath( GetXZPath2() );
 | 
						|
      }
 | 
						|
 | 
						|
      return convex2Group;
 | 
						|
    }
 | 
						|
 | 
						|
    public void ClearCurveCache()
 | 
						|
    {
 | 
						|
      splineCurve = null;
 | 
						|
      splineCurveXZ = null;
 | 
						|
      xzPath = null;
 | 
						|
      convex2Group = null;
 | 
						|
    }
 | 
						|
 | 
						|
#if TOOLS
 | 
						|
    
 | 
						|
    public void DrawGizmo( EditorNode3DGizmoPlugin gizmoPlugin, EditorNode3DGizmo gizmo )
 | 
						|
    {
 | 
						|
      ClearCurveCache();
 | 
						|
 | 
						|
      var curve = GetCurve();
 | 
						|
 | 
						|
      gizmo.Clear();
 | 
						|
 | 
						|
      if ( curve.points.Count <= 1 )
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      
 | 
						|
 | 
						|
      
 | 
						|
 | 
						|
      var linePoints = new List<Vector3>();
 | 
						|
 | 
						|
      int resolution = editorResolution <= 0 ? 20 : editorResolution;
 | 
						|
 | 
						|
      renderedResolution = editorResolution;
 | 
						|
 | 
						|
      var lastPoint = ToLocal( curve.PositionAt( 0 ) );
 | 
						|
 | 
						|
      for ( int i = 1; i < resolution; i++ )
 | 
						|
      {
 | 
						|
        var t = i / (float) (resolution - 1 );
 | 
						|
        var point = ToLocal( curve.PositionAt( t ) ); 
 | 
						|
 | 
						|
        linePoints.Add( lastPoint );
 | 
						|
        linePoints.Add( point );
 | 
						|
 | 
						|
        lastPoint = point;
 | 
						|
      }
 | 
						|
 | 
						|
      for ( int i = 0; i < curve.points.Count; i++ )
 | 
						|
      {
 | 
						|
        var p = curve.points[ i ];
 | 
						|
        linePoints.Add( ToLocal( p.position ) );
 | 
						|
        linePoints.Add( ToLocal( p.tangentBefore.position ) );
 | 
						|
 | 
						|
        linePoints.Add( ToLocal( p.position ) );
 | 
						|
        linePoints.Add( ToLocal( p.tangentNext.position ) );
 | 
						|
      }
 | 
						|
 | 
						|
      var material = gizmoPlugin.GetMaterial( "main", gizmo );
 | 
						|
 | 
						|
      gizmo.AddLines( linePoints.ToArray(), material, false );
 | 
						|
    }
 | 
						|
 | 
						|
    List<Vector3> cachedPositions = new List<Vector3>();
 | 
						|
    
 | 
						|
    
 | 
						|
    int renderedResolution = -100;
 | 
						|
 | 
						|
    
 | 
						|
 | 
						|
    public override void _Process( double delta )
 | 
						|
    {
 | 
						|
      var changed = updateAlways;
 | 
						|
      var index = 0;
 | 
						|
 | 
						|
      if ( renderedResolution != editorResolution )
 | 
						|
      {
 | 
						|
        changed = true;
 | 
						|
      }
 | 
						|
 | 
						|
      if ( autoOrienation )
 | 
						|
      {
 | 
						|
        AutoOrientate();        
 | 
						|
      }
 | 
						|
 | 
						|
      Nodes.ForEachDirectChild<SplinePoint>( this, 
 | 
						|
        sp => 
 | 
						|
        {
 | 
						|
          if ( changed )
 | 
						|
          {
 | 
						|
            return;
 | 
						|
          }
 | 
						|
 | 
						|
          if ( index >= cachedPositions.Count )
 | 
						|
          {
 | 
						|
            changed = true;
 | 
						|
            return;
 | 
						|
          }
 | 
						|
 | 
						|
          if ( cachedPositions[ index ] != sp.GlobalPosition )
 | 
						|
          {
 | 
						|
            changed = true;
 | 
						|
          }
 | 
						|
 | 
						|
          index ++;
 | 
						|
        }
 | 
						|
      );
 | 
						|
 | 
						|
      if ( ! changed )
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      cachedPositions = Nodes.MapDirectChildren<SplinePoint,Vector3>( this, sp => sp.GlobalPosition );
 | 
						|
 | 
						|
      // RJLog.Log( "Updating gizmos" );
 | 
						|
      UpdateGizmos();      
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    public void AutoOrientate()
 | 
						|
    {
 | 
						|
      var list = Nodes.GetDirectChildren<SplinePoint>( this );
 | 
						|
 | 
						|
      if ( list.Count <= 1 )
 | 
						|
      {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
        
 | 
						|
      var up = autoOrientationUp.Normalized();
 | 
						|
 | 
						|
      if ( SplineAutoOrientationMode.Next_Neighbor == autoOrientationMode )
 | 
						|
      {
 | 
						|
       
 | 
						|
 | 
						|
        for ( int i = 0; i < list.Count; i++ )
 | 
						|
        {
 | 
						|
          var point = list[ i ];
 | 
						|
 | 
						|
          if ( i == ( list.Count - 1 ) )
 | 
						|
          {
 | 
						|
            if ( closed )
 | 
						|
            {
 | 
						|
              var first = list[ 0 ];
 | 
						|
              var firstDirection = ( first.GlobalPosition - point.GlobalPosition ).Normalized();
 | 
						|
              point.LookTowards( firstDirection, up );
 | 
						|
            }
 | 
						|
 | 
						|
            continue;
 | 
						|
          }          
 | 
						|
 | 
						|
          var next = list[ i + 1 ];
 | 
						|
          
 | 
						|
          var direction = ( next.GlobalPosition - point.GlobalPosition ).Normalized();
 | 
						|
 | 
						|
          point.LookTowards( direction, up );
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else if ( SplineAutoOrientationMode.Tangent == autoOrientationMode )
 | 
						|
      {
 | 
						|
 | 
						|
        for ( int i = 0; i < list.Count; i++ )
 | 
						|
        {
 | 
						|
          var point = list[ i ];     
 | 
						|
 | 
						|
          var tangentForward = Vector3.Zero;
 | 
						|
 | 
						|
          if ( i == ( list.Count - 1 ) && ! closed )
 | 
						|
          {
 | 
						|
            tangentForward = - SplineCurveCreator.GetTangentDirectionSmoothed( 1, autoOrientationTangentAdjustment, list, i, true, false );
 | 
						|
          }
 | 
						|
          else
 | 
						|
          {
 | 
						|
            tangentForward = SplineCurveCreator.GetTangentDirectionSmoothed( 1, autoOrientationTangentAdjustment, list, i, false, closed );
 | 
						|
          }          
 | 
						|
          
 | 
						|
          if ( tangentForward.Length() == 0 )
 | 
						|
          {
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
 | 
						|
          point.LookTowards( tangentForward, up );
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
} |