293 lines
6.0 KiB
C#
293 lines
6.0 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
|
|
|
|
{
|
|
[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;
|
|
|
|
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
|
|
|
|
void AutoOrientate()
|
|
{
|
|
var list = Nodes.GetDirectChildren<SplinePoint>( this );
|
|
|
|
if ( list.Count <= 1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( SplineAutoOrientationMode.Next_Neighbor == autoOrientationMode )
|
|
{
|
|
for ( int i = 0; i < list.Count; i++ )
|
|
{
|
|
var sp = list[ i ];
|
|
|
|
if ( i == ( list.Count - 1 ) )
|
|
{
|
|
if ( closed )
|
|
{
|
|
var first = list[ 0 ];
|
|
sp.LookAt( first.GlobalPosition, autoOrientationUp );
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
var next = list[ i + 1 ];
|
|
sp.LookAt( next.GlobalPosition, autoOrientationUp );
|
|
}
|
|
}
|
|
else if ( SplineAutoOrientationMode.Tangent == autoOrientationMode )
|
|
{
|
|
|
|
for ( int i = 0; i < list.Count; i++ )
|
|
{
|
|
var sp = 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;
|
|
}
|
|
|
|
sp.LookAt( sp.GlobalPosition + tangentForward, autoOrientationUp );
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
} |