UI + Procedural Geometry
This commit is contained in:
		
							parent
							
								
									9a07e22b05
								
							
						
					
					
						commit
						575431f868
					
				|  | @ -0,0 +1,89 @@ | |||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
|   public abstract class GraphWalker<N> where N:class | ||||
|   { | ||||
|     public virtual int NumConnectedFrom( N node ){ return 0;} | ||||
|     public virtual N GetConnectedFrom( N node, int index ){ return default(N);} | ||||
| 
 | ||||
|     public abstract int NumConnectedTo( N node ); | ||||
|     public abstract N GetConnectedTo( N node, int index ); | ||||
| 
 | ||||
|     public int NumConnectedAll( N node ) | ||||
|     { | ||||
|       return NumConnectedTo( node ) + NumConnectedFrom( node ); | ||||
|     } | ||||
| 
 | ||||
|     public N GetConnected( N node, int index ) | ||||
|     { | ||||
|       var fromConnections = NumConnectedFrom( node ); | ||||
| 
 | ||||
|       return index < fromConnections ? GetConnectedFrom( node, index ) : GetConnectedTo( node, index - fromConnections ); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public bool IsConnectedTo( N source, N destination ) | ||||
|     { | ||||
|       var processed = new HashSet<N>(); | ||||
|       var toDo = new List<N>(); | ||||
| 
 | ||||
|       toDo.Add( source ); | ||||
| 
 | ||||
|       while ( toDo.Count > 0 ) | ||||
|       { | ||||
|         var current = Lists.RemoveFirst( toDo ); | ||||
|          | ||||
|         if ( processed.Contains( current ) ) | ||||
|         { | ||||
|           continue; | ||||
|         } | ||||
| 
 | ||||
|         processed.Add( current ); | ||||
| 
 | ||||
|         var numConnected = NumConnectedTo( current ); | ||||
|          | ||||
|         for ( int i = 0; i < numConnected; i++ ) | ||||
|         { | ||||
|           var connected = GetConnected( current, i ); | ||||
|            | ||||
|           if ( connected == destination ) | ||||
|           { | ||||
|             return true; | ||||
|           } | ||||
| 
 | ||||
|           if ( ! processed.Contains( connected ) ) | ||||
|           { | ||||
|             toDo.Add( connected ); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
|     public bool IsDirectlyConnectedTo( N node, N other ) | ||||
|     { | ||||
|       if ( node == null || other == null ) | ||||
|       { | ||||
|         return false; | ||||
|       } | ||||
| 
 | ||||
|       var connected = NumConnectedTo( node ); | ||||
| 
 | ||||
|       for ( int i = 0; i < connected; i++ ) | ||||
|       { | ||||
|         if ( GetConnected( node, i ) == other )  | ||||
|         { | ||||
|           return true; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -240,7 +240,7 @@ namespace Rokojori | |||
|       return NextNonChild( node ); | ||||
|     } | ||||
| 
 | ||||
|     public N GetParent( N node, Func<N,bool> predicate ) | ||||
|     public N GetInParents( N node, Func<N,bool> predicate ) | ||||
|     { | ||||
|       var p = Parent( node ); | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,6 +42,13 @@ namespace Rokojori | |||
|       GD.PrintRich( trace ); | ||||
|     } | ||||
| 
 | ||||
|     static void LogMessageWithFullTrace( string message ) | ||||
|     { | ||||
|       var trace = GetFullTrace(); | ||||
|       GD.PrintRich("\n[b]" +  message + "[/b]"); | ||||
|       GD.PrintRich( trace ); | ||||
|     } | ||||
| 
 | ||||
|     static void LogErrorMessage( string message ) | ||||
|     { | ||||
|       var trace = GetTrace(); | ||||
|  | @ -49,6 +56,11 @@ namespace Rokojori | |||
|       GD.PrintRich( trace ); | ||||
|     } | ||||
| 
 | ||||
|     static string GetFullTrace() | ||||
|     { | ||||
|       return ( new System.Diagnostics.StackTrace( true ) ).ToString(); | ||||
|     } | ||||
| 
 | ||||
|     static string GetTrace() | ||||
|     { | ||||
|       var stackTrace = new System.Diagnostics.StackTrace( true ); | ||||
|  | @ -86,6 +98,23 @@ namespace Rokojori | |||
|       return "[color=gray]  " + trace + "[/color]" ; | ||||
|     } | ||||
| 
 | ||||
|     public static void LogWithFullTrace( params object[] objects) | ||||
|     { | ||||
|       var sb = new StringBuilder(); | ||||
| 
 | ||||
|       for ( int i = 0; i < objects.Length; i++ ) | ||||
|       { | ||||
|         if ( i != 0 ) | ||||
|         { | ||||
|           sb.Append( " " );  | ||||
|         } | ||||
| 
 | ||||
|         Stringify( objects[ i ], sb ); | ||||
|       } | ||||
| 
 | ||||
|       LogMessageWithFullTrace( sb.ToString() ); | ||||
|     } | ||||
| 
 | ||||
|     public static void Log( params object[] objects) | ||||
|     { | ||||
|       var sb = new StringBuilder(); | ||||
|  |  | |||
|  | @ -0,0 +1,44 @@ | |||
| using Godot; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
| 	public class Capsule3 | ||||
| 	{ | ||||
|     public Vector3 start = Vector3.Zero; | ||||
|     public Vector3 end = Vector3.Zero; | ||||
|     public float radius = 1; | ||||
| 
 | ||||
|     public Capsule3( Vector3 start, Vector3 end, float radius ) | ||||
|     { | ||||
|       this.start = start; | ||||
|       this.end = end; | ||||
|       this.radius = radius; | ||||
|     }     | ||||
| 
 | ||||
|     public Capsule3 Copy() | ||||
|     { | ||||
|       return new Capsule3( start, end, radius ); | ||||
|     } | ||||
| 
 | ||||
|     public Vector3 center | ||||
|     { | ||||
|       get { return start.Lerp( end, 0.5f ); } | ||||
|     } | ||||
| 
 | ||||
|     public Line3 centerLine | ||||
|     { | ||||
|       get { return new Line3( start, end ); } | ||||
|     } | ||||
| 
 | ||||
|     public float DistanceToPoint( Vector3 p ) | ||||
|     { | ||||
|       var lineDistance = centerLine.DistanceToPoint( p ); | ||||
|       return Mathf.Max( 0, lineDistance - radius ); | ||||
|     }  | ||||
| 
 | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,77 @@ | |||
| using Godot; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
| 	public abstract class Curve3 | ||||
| 	{ | ||||
|     float _gradientSamplingRange = Mathf.Pow( 10f, -13f ); | ||||
|     public abstract Vector3 SampleAt( float t ); | ||||
|      | ||||
|     public virtual void SampleMultiple( int numSamples, List<Vector3> output ) | ||||
|     { | ||||
|       SampleMultiple( new Range( 0, 1 ), numSamples, output ); | ||||
|     } | ||||
|      | ||||
|     public virtual void SampleMultiple( Range range, int numSamples, List<Vector3> output ) | ||||
|     { | ||||
| 
 | ||||
|       var diff = range.length / ( numSamples - 1 ) ; | ||||
|        | ||||
|       for ( var i = 0 ; i < numSamples; i++ ) | ||||
|       { | ||||
|         var t = range.min + i * diff; | ||||
|         output.Add( SampleAt( t ) ); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     public virtual Vector3 GradientAt( float t ) | ||||
|     { | ||||
| 
 | ||||
|       return SampleAt( t + _gradientSamplingRange ) - SampleAt( t - _gradientSamplingRange ); | ||||
|     } | ||||
| 
 | ||||
|     public virtual float ComputeLength( int numSamples ) | ||||
|     { | ||||
|       return ComputeSubLength( Range.Of_01 , numSamples ); | ||||
|     }     | ||||
| 
 | ||||
|     public virtual float ComputeSubLength( Range range, int numSamples ) | ||||
|     { | ||||
|       var diff = range.length / ( numSamples - 1 ) ; | ||||
|       var it = SampleAt( range.min ); | ||||
|       var length = 0f; | ||||
| 
 | ||||
|       for ( var i = 1 ; i < numSamples; i++ ) | ||||
|       { | ||||
|         var t = range.min + i * diff; | ||||
|         var next = SampleAt( t ); | ||||
|         length += ( next - it ).Length(); | ||||
|         it = next; | ||||
|       } | ||||
| 
 | ||||
|       return length; | ||||
|     } | ||||
|      | ||||
|     public virtual int ComputeNumSamplesFor( Range range, | ||||
|     float minimumDistance, int minSamples = 2,  | ||||
|     int numSamplesForLengthComputation = -1 ) | ||||
|     { | ||||
|       if ( minSamples < 2 ) | ||||
|       { minSamples = 2; } | ||||
|        | ||||
|       if ( numSamplesForLengthComputation <= 0  ) | ||||
|       { numSamplesForLengthComputation = minSamples * 4; } | ||||
| 
 | ||||
|       float distance = ComputeSubLength( range, numSamplesForLengthComputation ); | ||||
|       float numFloatingCuts = distance / minimumDistance; | ||||
|       int numSamples = Mathf.CeilToInt( numFloatingCuts ); | ||||
| 
 | ||||
|       return Mathf.Max( minSamples, numSamples ); | ||||
|     } | ||||
| 
 | ||||
|          | ||||
|          | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,117 @@ | |||
| using Godot; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
| 	public class Distance | ||||
| 	{ | ||||
|      | ||||
|     /* | ||||
|      | ||||
|     P = Point,  | ||||
|     S = Sphere | ||||
|     L = Line, | ||||
|     C = Capsule | ||||
| 
 | ||||
|      | ||||
|       P S L C    | ||||
|     P y y y y    | ||||
|     S   y y y       | ||||
|     L     y y       | ||||
|     C       y   | ||||
| 
 | ||||
|     */ | ||||
| 
 | ||||
|     public static float Of( Vector3 a, Vector3 b ) | ||||
|     { | ||||
|       return ( a - b ).Length(); | ||||
|     }     | ||||
| 
 | ||||
|     public static float Of( Vector3 a, Sphere b ) | ||||
|     { | ||||
|       return b.DistanceToPoint( a ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Sphere a, Vector3 b ) | ||||
|     { | ||||
|       return Of( b, a ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Vector3 a, Line3 b ) | ||||
|     { | ||||
|       return b.DistanceToPoint( a ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Line3 b, Vector3 a ) | ||||
|     { | ||||
|       return Of( a, b ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Vector3 a, Capsule3 b ) | ||||
|     { | ||||
|       return b.DistanceToPoint( a ); | ||||
|     } | ||||
|      | ||||
|     public static float Of( Capsule3 a, Vector3 b ) | ||||
|     { | ||||
|       return Of( b, a ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Sphere a, Sphere b ) | ||||
|     { | ||||
|       return a.DistanceToSphere( b ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Sphere a, Line3 b ) | ||||
|     { | ||||
|       var centerDistance = Of( a.center, b ); | ||||
|       return Mathf.Max( centerDistance - a.radius, 0 );  | ||||
|     }  | ||||
| 
 | ||||
|     public static float Of( Line3 a, Sphere b ) | ||||
|     { | ||||
|       return Of( b, a ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Sphere a, Capsule3 b ) | ||||
|     { | ||||
|       var centerDistance = Of( a.center, b ); | ||||
|       return Mathf.Max( centerDistance - a.radius, 0 );  | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Capsule3 a, Sphere b ) | ||||
|     { | ||||
|       return Of( b, a ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Line3 a, Line3 b ) | ||||
|     { | ||||
|       return a.DistanceToLine( b ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Line3 a, Capsule3 b ) | ||||
|     { | ||||
|       var lineDistance = Of( a, b.centerLine ); | ||||
|       return Mathf.Max( 0, lineDistance - b.radius ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Capsule3 a, Line3 b ) | ||||
|     { | ||||
|       return Of( b, a ); | ||||
|     } | ||||
| 
 | ||||
|     public static float Of( Capsule3 a, Capsule3 b ) | ||||
|     { | ||||
|       var lineDistance = Of( a.centerLine, b.centerLine ); | ||||
|       return Mathf.Max( 0, lineDistance - ( a.radius + b.radius ) ); | ||||
|     } | ||||
|      | ||||
|      | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,249 @@ | |||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using Godot; | ||||
| 
 | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
| 
 | ||||
|   public class SubdivisionData | ||||
|   { | ||||
|     public Vector3 point; | ||||
|     public bool isCorner; | ||||
|     public Vector3 direction; | ||||
| 
 | ||||
|     public SubdivisionData( Vector3 p, Vector3 d, bool corner = false ) | ||||
|     { | ||||
|       point = p; | ||||
|       direction = d; | ||||
|       isCorner = corner; | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   public class LerpCurveClosestToPointResult | ||||
|   { | ||||
|     public float parameter; | ||||
|     public float distance; | ||||
|     public Vector3 point; | ||||
|   } | ||||
| 
 | ||||
| 	public class LerpCurve3:Curve3 | ||||
| 	{ | ||||
|     List<Vector3> list; | ||||
|      | ||||
|     public LerpCurve3( List<Vector3> list ) | ||||
|     { | ||||
|       this.list = list; | ||||
|        | ||||
|       if ( list.Count == 0 ) | ||||
|       { | ||||
|         RJLog.Log( "LERP CURVE WITH EMPTY LIST" ); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     public override float ComputeLength( int numSamples ) | ||||
|     { | ||||
|       var length = 0f; | ||||
|       var end = list.Count - 1; | ||||
| 
 | ||||
|       for ( int i = 0; i < end; i++ ) | ||||
|       { | ||||
|         var p0  = list[ i ]; | ||||
|         var p1  = list[ i + 1 ]; | ||||
| 
 | ||||
|         length += p0.DistanceTo( p1 ); | ||||
|       } | ||||
| 
 | ||||
|       return length; | ||||
|     } | ||||
| 
 | ||||
|     public float UndistortParameter( float parameter ) | ||||
|     { | ||||
|       var completeLength = ComputeLength( 0 ); | ||||
| 
 | ||||
|       var end = list.Count - 1; | ||||
|       var normalizer = 1f / ( list.Count - 1 ); | ||||
| 
 | ||||
|       var length = 0f; | ||||
| 
 | ||||
|       for ( int i = 0; i < end; i++ ) | ||||
|       { | ||||
|         var p0  = list[ i ]; | ||||
|         var p1  = list[ i + 1 ]; | ||||
|         var t0  = i * normalizer; | ||||
|         var t1  = ( i + 1 ) * normalizer; | ||||
|         var distance = p0.DistanceTo( p1 ); | ||||
| 
 | ||||
|         if ( t0 <= parameter && parameter <= t1 ) | ||||
|         { | ||||
|           length += distance * ( parameter - t0 );  | ||||
|           return length / completeLength; | ||||
|         } | ||||
| 
 | ||||
|         length += distance; | ||||
| 
 | ||||
|       } | ||||
| 
 | ||||
|       return 1; | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public List<SubdivisionData> Subdivide( float distance, bool close ) | ||||
|     { | ||||
|       var output = new List<SubdivisionData>(); | ||||
| 
 | ||||
|       var num = list.Count - 1; | ||||
| 
 | ||||
|       if ( close ) | ||||
|       { | ||||
|         num ++; | ||||
|       } | ||||
| 
 | ||||
|       for ( var i = 0; i < num; i++ ) | ||||
|       { | ||||
|         var start = list[ i ]; | ||||
|         var end   = list[ i == list.Count ? 0 : i + 1 ]; | ||||
| 
 | ||||
|         var dir = ( end - start ); | ||||
|         var length = dir.Length(); | ||||
|         var samples = Mathf.CeilToInt( length / distance ); | ||||
| 
 | ||||
|         output.Add( new SubdivisionData( start, dir, true ) ); | ||||
| 
 | ||||
|         for ( int j = 1; j < samples; j++ ) | ||||
|         { | ||||
|           var samplePoint = j / (float) samples; | ||||
|           var point = start.Lerp( end, samplePoint ); | ||||
|           output.Add( new SubdivisionData( point, dir ) ); | ||||
|         } | ||||
|          | ||||
|       } | ||||
|        | ||||
| 
 | ||||
|       if ( ! close ) | ||||
|       { | ||||
|         var start = list[ list.Count - 2]; | ||||
|         var end   = list[ list.Count - 1]; | ||||
| 
 | ||||
|         var dir = ( end - start ); | ||||
| 
 | ||||
|         output.Add( new SubdivisionData( end, dir, true ) ); | ||||
|          | ||||
|       } | ||||
| 
 | ||||
| 
 | ||||
|       var dirCount = close ? output.Count : ( output.Count - 1 ); | ||||
| 
 | ||||
|       for ( int i = 0; i < dirCount; i++ ) | ||||
|       { | ||||
|         var next = i == output.Count ? 0 : i + 1; | ||||
|         output[ i ].direction = output[ next ].point - output[ i ].point; | ||||
|       } | ||||
|        | ||||
| 
 | ||||
|        | ||||
| 
 | ||||
|       return output; | ||||
|     } | ||||
| 
 | ||||
|     public override Vector3 SampleAt( float t ) | ||||
|     { | ||||
|       if ( t < 0 ) | ||||
|       { | ||||
|         return list[ 0 ]; | ||||
|       } | ||||
|        | ||||
|       if ( t >= 1 ) | ||||
|       { | ||||
|         return list[ list.Count - 1 ]; | ||||
|       } | ||||
| 
 | ||||
|       if ( list.Count == 1 ) | ||||
|       { | ||||
|         return list[ 0 ]; | ||||
|       } | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
|       var listIndex = t * ( list.Count - 1 ); | ||||
|       var flooredIndex = (int) Mathf.Floor( listIndex ); | ||||
| 
 | ||||
|       var lerpAmount = listIndex - flooredIndex; | ||||
| 
 | ||||
|       if ( flooredIndex < 0 ||  ( flooredIndex >= list.Count - 1 ) ) | ||||
|       { | ||||
|         RJLog.Log( "Out of range index:",flooredIndex, " t:", t, " listIndex", listIndex, "Count:", list.Count ); | ||||
|       } | ||||
| 
 | ||||
|       var lower = list[ flooredIndex ]; | ||||
|       var upper = list[ flooredIndex + 1 ]; | ||||
| 
 | ||||
|       return Math3D.LerpUnclamped( lower, upper, lerpAmount ); | ||||
|        | ||||
|     } | ||||
| 
 | ||||
|     public LerpCurve3 FromRange( Curve3 curve, Range range, int numSamples ) | ||||
|     { | ||||
|       var points = new List<Vector3>(); | ||||
|       curve.SampleMultiple( range, numSamples, points ); | ||||
|       return new LerpCurve3( points ); | ||||
|     } | ||||
| 
 | ||||
|     public LerpCurve3 From( Curve3 curve, int numSamples ) | ||||
|     { | ||||
|       return FromRange( curve, Range.Of_01, numSamples ); | ||||
|     } | ||||
| 
 | ||||
|     public static LerpCurve3 FromPoints( Vector3 first, Vector3 second, params Vector3[] others ) | ||||
|     { | ||||
|       var points = new List<Vector3>(); | ||||
|       points.Add( first ); | ||||
|       points.Add( second ); | ||||
|       points.AddRange( others ); | ||||
| 
 | ||||
|       return new LerpCurve3( points ); | ||||
|     } | ||||
| 
 | ||||
|     Line3 line; | ||||
| 
 | ||||
|     public void GetClosest( Vector3 point, LerpCurveClosestToPointResult result ) | ||||
|     { | ||||
|       var closestDistance = float.MaxValue; | ||||
|       Vector3 closestPoint    = Vector3.Zero;  | ||||
|       var closestParameter  = 0f; | ||||
| 
 | ||||
|       if ( line == null ) | ||||
|       { | ||||
|         line = new Line3( Vector3.Zero, Vector3.Zero ); | ||||
|       } | ||||
| 
 | ||||
|       var end = list.Count - 1; | ||||
|        | ||||
|       var parameterNormalizer = 1f / ( list.Count - 1f ); | ||||
| 
 | ||||
|       for ( int i = 0; i < end; i++ ) | ||||
|       {         | ||||
|         line.start = list[ i ]; | ||||
|         line.end   = list[ i + 1 ]; | ||||
| 
 | ||||
|         var currentParameter = line.ClostestParameterToPoint( point ); | ||||
|         var currentClosestPoint = line.GetPointAtParameter( currentParameter ); | ||||
|         var currentDistance = ( point - currentClosestPoint ).LengthSquared(); | ||||
| 
 | ||||
|         if ( currentDistance < closestDistance ) | ||||
|         { | ||||
|           closestDistance = currentDistance; | ||||
|           closestPoint = currentClosestPoint; | ||||
|           closestParameter = ( currentParameter + i ) * parameterNormalizer; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       result.distance = Mathf.Sqrt( closestDistance ); | ||||
|       result.point = closestPoint; | ||||
|       result.parameter = closestParameter; | ||||
| 
 | ||||
|     } | ||||
|          | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,198 @@ | |||
| using Godot; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
|   public class Line3:Curve3 | ||||
|   { | ||||
|     public Vector3 start = Vector3.Zero; | ||||
|     public Vector3 end = Vector3.Zero; | ||||
| 
 | ||||
|     public Line3( Vector3 start, Vector3 end ) | ||||
|     { | ||||
|       this.start = start; | ||||
|       this.end = end; | ||||
|     }  | ||||
| 
 | ||||
|     public override Vector3 SampleAt( float t ) | ||||
|     { | ||||
|       return start.Lerp( end, t ); | ||||
|     } | ||||
| 
 | ||||
|     public Line3 Copy( ) | ||||
|     { | ||||
|       return new Line3( start, end ); | ||||
|     } | ||||
| 
 | ||||
|     public Vector3 direction { get { return end - start; } } | ||||
| 
 | ||||
|     public float length { get { return direction.Length();  } } | ||||
|      | ||||
|     public Vector3 GetPointAtParameter( float t ) | ||||
|     { | ||||
|       return start + direction * t; | ||||
|     } | ||||
| 
 | ||||
|     public Vector3 center{ get { return ( start + end ) * 0.5f; } } | ||||
| 
 | ||||
|     public Line3 ScaleFromCenter( float scale ) | ||||
|     { | ||||
|       var lineCenter = center; | ||||
|       var halfDirection = direction * ( 0.5f * scale ); | ||||
| 
 | ||||
|       var scaledStart = lineCenter - halfDirection; | ||||
|       var scaledEnd   = lineCenter + halfDirection; | ||||
| 
 | ||||
|       return new Line3( scaledStart, scaledEnd );   | ||||
|     } | ||||
| 
 | ||||
|     public Line3 ChangeLengthFromCenter( float lengthChange ) | ||||
|     { | ||||
|       var lineCenter = center; | ||||
|       var halfDirection = direction * 0.5f; | ||||
|       var length = halfDirection.Length(); | ||||
|       length += lengthChange * 0.5f; | ||||
| 
 | ||||
|       halfDirection = halfDirection.Normalized() * length;       | ||||
| 
 | ||||
|       var scaledStart = lineCenter - halfDirection; | ||||
|       var scaledEnd   = lineCenter + halfDirection; | ||||
| 
 | ||||
|       return new Line3( scaledStart, scaledEnd );   | ||||
|     } | ||||
| 
 | ||||
|     public Line3 SetLengthFromCenter( float length ) | ||||
|     { | ||||
|       var lineCenter = center; | ||||
|       var halfDirection = direction.Normalized() * ( length * 0.5f );      | ||||
| 
 | ||||
|       var scaledStart = lineCenter - halfDirection; | ||||
|       var scaledEnd   = lineCenter + halfDirection; | ||||
| 
 | ||||
|       return new Line3( scaledStart, scaledEnd );   | ||||
|     } | ||||
|      | ||||
|       | ||||
|     public Vector3 ClosestPointToPoint( Vector3 point ) | ||||
|     { | ||||
|       var parameter = MathX.Clamp01( ClostestParameterToPoint( point ) ); | ||||
|       return GetPointAtParameter( parameter ); | ||||
|     } | ||||
| 
 | ||||
|     public float ClostestParameterToPoint( Vector3 point ) | ||||
|     { | ||||
|       var startP = point - start; | ||||
|       var startEnd = end - start; | ||||
|       var startEnd2 = startEnd.Dot( startEnd ); | ||||
|       var startEnd_startP = startEnd.Dot( startP ); | ||||
| 
 | ||||
|       if ( startEnd2 == 0 ) | ||||
|       { | ||||
|         return 0; | ||||
|       } | ||||
| 
 | ||||
|       var t = startEnd_startP / startEnd2; | ||||
| 
 | ||||
|       return t; | ||||
|          | ||||
|     } | ||||
| 
 | ||||
|     public float DistanceToPoint( Vector3 point ) | ||||
|     { | ||||
|       return ( point - ClosestPointToPoint( point ) ).Length(); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public float DistanceToLine( Line3 s ) | ||||
|     { | ||||
|       var points = ClosestPointsToLine( s ); | ||||
|       return ( points[ 1 ] - points[ 0 ] ).Length(); | ||||
|     } | ||||
| 
 | ||||
|     public Vector3[] ClosestPointsToLine( Line3 s ) | ||||
|     { | ||||
|       var parameters = ClosestParametersToLine( s ); | ||||
|       var x = this.GetPointAtParameter( parameters.X ); | ||||
|       var y = s.GetPointAtParameter( parameters.Y ); | ||||
| 
 | ||||
|       return new Vector3[]{ x, y };   | ||||
|     } | ||||
| 
 | ||||
|     public Vector2 ClosestParametersToLine( Line3 s ) | ||||
|     {      | ||||
|       float epsilon = 0.00000001f; | ||||
| 
 | ||||
|       var u = this.direction; | ||||
|       var v = s.direction; | ||||
|       var w = start - s.start; | ||||
|      | ||||
|       var a = u.Dot( u ); | ||||
|       var b = u.Dot( v ); | ||||
|       var c = v.Dot( v ); | ||||
|       var d = u.Dot( w ); | ||||
|       var e = v.Dot( w ); | ||||
| 
 | ||||
|       var DD = a * c - b * b; | ||||
| 
 | ||||
|       var sc = 0f; | ||||
|       var sN = 0f; | ||||
|       var sD = 0f; | ||||
| 
 | ||||
|       var tc = 0f; | ||||
|       var tN = 0f; | ||||
|       var tD = 0f; | ||||
| 
 | ||||
|       sD = DD; | ||||
|       tD = DD; | ||||
| 
 | ||||
|       if ( DD < epsilon )  | ||||
|       { | ||||
|         sN = 0.0f; | ||||
|         sD = 1.0f; | ||||
|         tN = e; | ||||
|         tD = c; | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         sN = b * e - c * d ; | ||||
|         tN = a * e - b * d ; | ||||
| 
 | ||||
|         if ( sN < 0.0f ) | ||||
|         { | ||||
|           sN = 0.0f; | ||||
|           tN = e; | ||||
|           tD = c; | ||||
|         } | ||||
|         else if ( sN > sD )  | ||||
|         { | ||||
|           sN = sD; | ||||
|           tN = e + b; | ||||
|           tD = c; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if ( tN < 0f || tN > tD ) | ||||
|       { | ||||
|         var tN_bigger_tD = tN >= 0f && tN > tD; | ||||
| 
 | ||||
|         tN = tN_bigger_tD ? tD : 0f; | ||||
| 
 | ||||
|         var inbetween = tN_bigger_tD ? ( -d + b ) : ( -d ); | ||||
|         var isSmaller = inbetween < 0; | ||||
|         var isBigger  = inbetween > a; | ||||
| 
 | ||||
|         sN = isSmaller ? 0f : isBigger ? sD : inbetween;  | ||||
|         sD = ! isSmaller && ! isBigger ?  a : sD; | ||||
|       } | ||||
| 
 | ||||
|       sc = Mathf.Abs( sN ) < epsilon ? 0f : sN / sD; | ||||
|       tc = Mathf.Abs( tN ) < epsilon ? 0f : tN / tD; | ||||
| 
 | ||||
|       return new Vector2( sc, tc );  | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,53 @@ | |||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using Godot; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
| 	public class Sphere | ||||
| 	{ | ||||
|     public Vector3 center = Vector3.Zero; | ||||
|     public float radius = 1; | ||||
| 
 | ||||
|     public Sphere( Vector3 center, float radius ) | ||||
|     { | ||||
|       this.center = center; | ||||
|       this.radius = radius; | ||||
|     }     | ||||
| 
 | ||||
|     public Sphere Copy() | ||||
|     { | ||||
|       return new Sphere( center, radius ); | ||||
|     } | ||||
| 
 | ||||
|     public float DistanceToPoint( Vector3 point ) | ||||
|     { | ||||
|       return Mathf.Max( 0, ( point - center ).Length() - radius ); | ||||
|     } | ||||
| 
 | ||||
|     public bool ContainsPoint( Vector3 point ) | ||||
|     { | ||||
|       return DistanceToPoint( point ) <= 0;  | ||||
|     } | ||||
| 
 | ||||
|     public float DistanceToSphere( Sphere sphere ) | ||||
|     { | ||||
|       var distance = sphere.center - center; | ||||
|       var radiusBoth = sphere.radius + radius; | ||||
|       return Mathf.Max( 0, distance.Length() - radiusBoth );  | ||||
|     } | ||||
| 
 | ||||
|     public bool IntersectsSphere( Sphere sphere ) | ||||
|     { | ||||
|       return DistanceToSphere( sphere ) <= 0; | ||||
|     } | ||||
| 
 | ||||
|     public Box3 CreateBox() | ||||
|     { | ||||
|       var offset = radius * Vector3.One; | ||||
|       return Box3.Create( center -offset, center + offset ); | ||||
|     } | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,96 @@ | |||
| using Godot; | ||||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
|   public enum TriangleSide | ||||
|   { | ||||
|     AB, | ||||
|     BC, | ||||
|     CA | ||||
|   } | ||||
|    | ||||
|   public class TriangleSides | ||||
|   { | ||||
|     public static readonly TriangleSide[] ALL =  | ||||
|     { | ||||
|       TriangleSide.AB, | ||||
|       TriangleSide.BC, | ||||
|       TriangleSide.CA | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   public class Triangle3 | ||||
|   {    | ||||
|     public Vector3 a; | ||||
|     public Vector3 b; | ||||
|     public Vector3 c; | ||||
| 
 | ||||
|     public Triangle3( Vector3 a, Vector3 b, Vector3 c ) | ||||
|     { | ||||
|       this.a = a; | ||||
|       this.b = b; | ||||
|       this.c = c; | ||||
|     } | ||||
| 
 | ||||
|     public float perimeter | ||||
|     { | ||||
|       get | ||||
|       { | ||||
|         var sideA = ( b - a ).Length(); | ||||
|         var sideB = ( c - b ).Length(); | ||||
|         var sideC = ( a - c ).Length(); | ||||
|        | ||||
|         return sideA + sideB + sideC; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     public float semiperimeter | ||||
|     { | ||||
|       get | ||||
|       { | ||||
|         return perimeter * 0.5f; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     public static float ComputeTriangleArea( Vector3 a, Vector3 b, Vector3 c ) | ||||
|     { | ||||
|       var sideA = ( b - a ).Length(); | ||||
|       var sideB = ( c - b ).Length(); | ||||
|       var sideC = ( a - c ).Length(); | ||||
|      | ||||
| 
 | ||||
|       var perimeter = sideA + sideB + sideC; | ||||
|       var semiperimeter = 0.5f * perimeter; | ||||
|       var areaValue = Mathf.Sqrt( semiperimeter * ( semiperimeter - sideA )  | ||||
|                                                 * ( semiperimeter - sideB )  | ||||
|                                                 * ( semiperimeter - sideC )) ; | ||||
| 
 | ||||
|       return areaValue;    | ||||
|     } | ||||
| 
 | ||||
|     public float area | ||||
|     { | ||||
|       get | ||||
|       { | ||||
|         return ComputeTriangleArea( a, b, c ); | ||||
|       }      | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public Line3 GetSide( TriangleSide side ) | ||||
|     {  | ||||
|       switch ( side ) | ||||
|       { | ||||
|         case TriangleSide.AB: return new Line3( a, b ); | ||||
|         case TriangleSide.BC: return new Line3( b, c  ); | ||||
|         case TriangleSide.CA: return new Line3( c, a ); | ||||
|       } | ||||
| 
 | ||||
|       return null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| } | ||||
|  | @ -8,6 +8,16 @@ namespace Rokojori | |||
| { | ||||
|   public class Math3D | ||||
|   { | ||||
|     public static Vector3 LerpUnclamped( Vector3 a, Vector3 b, float amount ) | ||||
|     { | ||||
|       return a + amount * ( b - a ); | ||||
|     } | ||||
| 
 | ||||
|     public static Vector3 LerpClamped( Vector3 a, Vector3 b, float amount ) | ||||
|     { | ||||
|       return LerpUnclamped( a, b, MathX.Clamp01( amount ) ); | ||||
|     } | ||||
| 
 | ||||
|     public static Quaternion GetGlobalRotation( Node3D node ) | ||||
|     { | ||||
|       return node.GlobalBasis.GetRotationQuaternion(); | ||||
|  |  | |||
|  | @ -0,0 +1,104 @@ | |||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using Godot; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
| 
 | ||||
|   public class RationalCubicBezier | ||||
|   { | ||||
|     public static float Compute( | ||||
|       float t,  | ||||
|       float p0, float p1, float p2, float p3,  | ||||
|       float w0, float w1, float w2, float w3 | ||||
|     ) | ||||
|     { | ||||
|       var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * w0; | ||||
|       var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * w1; | ||||
|       var bp2 = 3 * ( 1 - t ) * t * t * w2; | ||||
|       var bp3 = t * t * t * w3; | ||||
| 
 | ||||
|       var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3; | ||||
| 
 | ||||
|       var projection = bp0 + bp1 + bp2 + bp3; | ||||
| 
 | ||||
|       return weighted / projection; | ||||
|     } | ||||
| 
 | ||||
|     public static Vector2 Compute( | ||||
|       float t,  | ||||
|       Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3,  | ||||
|       float w0, float w1, float w2, float w3 | ||||
|     ) | ||||
|     { | ||||
|       var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * w0; | ||||
|       var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * w1; | ||||
|       var bp2 = 3 * ( 1 - t ) * t * t * w2; | ||||
|       var bp3 = t * t * t * w3; | ||||
| 
 | ||||
|       var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3; | ||||
| 
 | ||||
|       var projection = bp0 + bp1 + bp2 + bp3; | ||||
| 
 | ||||
|       return weighted / projection; | ||||
|     } | ||||
| 
 | ||||
|     public static Vector3 Compute( | ||||
|       float t,  | ||||
|       Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3,  | ||||
|       float w0, float w1, float w2, float w3 | ||||
|     ) | ||||
|     { | ||||
|       var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * w0; | ||||
|       var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * w1; | ||||
|       var bp2 = 3 * ( 1 - t ) * t * t * w2; | ||||
|       var bp3 = t * t * t * w3; | ||||
| 
 | ||||
|       var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3; | ||||
| 
 | ||||
|       var projection = bp0 + bp1 + bp2 + bp3; | ||||
| 
 | ||||
|       return weighted / projection; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public static Vector2 Compute( float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3 ) | ||||
|     { | ||||
|       var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * p0.Z; | ||||
|       var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * p1.Z; | ||||
|       var bp2 = 3 * ( 1 - t ) * t * t * p2.Z; | ||||
|       var bp3 = t * t * t * p3.Z; | ||||
| 
 | ||||
|       var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3; | ||||
| 
 | ||||
|       var projection = bp0 + bp1 + bp2 + bp3; | ||||
| 
 | ||||
|       var result = weighted / projection; | ||||
| 
 | ||||
|       return new Vector2( result.X, result.Y ); | ||||
|     } | ||||
| 
 | ||||
|     public static Vector3 Compute( float t, Vector4 p0, Vector4 p1, Vector4 p2, Vector4 p3 ) | ||||
|     { | ||||
|       var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * p0.W; | ||||
|       var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * p1.W; | ||||
|       var bp2 = 3 * ( 1 - t ) * t * t * p2.W; | ||||
|       var bp3 = t * t * t * p3.W; | ||||
| 
 | ||||
|       var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3; | ||||
| 
 | ||||
|       var projection = bp0 + bp1 + bp2 + bp3; | ||||
| 
 | ||||
|       var result = weighted / projection; | ||||
| 
 | ||||
|       return new Vector3( result.X, result.Y, result.Z ); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
|      | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,20 @@ | |||
| Match:   \.magnitude | ||||
| Replace: .Length() | ||||
| 
 | ||||
| Match:   \.normalized | ||||
| Replace: .Normalized() | ||||
| 
 | ||||
| Match:   Vector3\.(Lerp|Dot)\(\s*(\w+)\s*,\s* | ||||
| Replace: $2.$1(  | ||||
| 
 | ||||
| Match:   Vector3\.Distance\(\s*(\w+)\s*,\s* | ||||
| Replace: $1.DistanceTo(  | ||||
| 
 | ||||
| Match:   \.x | ||||
| Replace: .X | ||||
| 
 | ||||
| Match:   \.Y | ||||
| Replace: .Y | ||||
| 
 | ||||
| Match:   \.z | ||||
| Replace: .Z | ||||
|  | @ -0,0 +1,138 @@ | |||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using Godot; | ||||
| using System; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
|   public class MeshGeometry | ||||
|   { | ||||
|     public List<Vector3> vertices; | ||||
|     public List<int> indices; | ||||
| 
 | ||||
|     public List<Vector3> normals; | ||||
|     public List<Vector2> uvs; | ||||
|     public List<Vector2> uv2s; | ||||
|     public List<Color> colors; | ||||
|    | ||||
| 
 | ||||
|     public void Initialize( bool normals = true, bool uvs = true, bool colors = false, bool uvs2 = false) | ||||
|     { | ||||
|       this.vertices = new List<Vector3>(); | ||||
|       this.indices = new List<int>(); | ||||
|        | ||||
|       this.normals = normals ? new List<Vector3>() : null; | ||||
|       this.uvs = uvs ? new List<Vector2>() : null; | ||||
|       this.uv2s = uvs2 ? new List<Vector2>() : null; | ||||
|       this.colors = colors ? new List<Color>() : null;       | ||||
|     } | ||||
| 
 | ||||
|     public void AddTriangle(  | ||||
|       Vector3 va, Vector3 vb, Vector3 vc,  | ||||
|       Vector3 na, Vector3 nb, Vector3 nc, | ||||
|       Vector2 uva, Vector2 uvb, Vector2 uvc | ||||
|     ) | ||||
|     { | ||||
|       var index = vertices.Count; | ||||
|       Lists.Add( vertices, va, vb, vc ); | ||||
|       Lists.Add( normals, na, nb, nc ); | ||||
|       Lists.Add( uvs, uva, uvb, uvc ); | ||||
|       Lists.Add( indices, index, index + 1, index + 2 ); | ||||
|     } | ||||
| 
 | ||||
|     public void AddQuad( | ||||
|       Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd, | ||||
|       Vector3 na, Vector3 nb, Vector3 nc, Vector3 nd,  | ||||
|       Vector2 uva, Vector2 uvb, Vector2 uvc, Vector2 uvd | ||||
|     ) | ||||
|     { | ||||
|       AddTriangle( va, vb, vc,  na, nb, nc,  uva, uvb, uvc ); | ||||
|       AddTriangle( vc, vd, va,  nc, nd, na,  uvc, uvd, uva ); | ||||
|     } | ||||
| 
 | ||||
|     public void AddTriangle(  | ||||
|       Vector3 va, Vector3 vb, Vector3 vc,  | ||||
|       Vector2 uva, Vector2 uvb, Vector2 uvc | ||||
|     ) | ||||
|     { | ||||
|       var n = Vector3.Up; | ||||
| 
 | ||||
|       AddTriangle( va, vb, vc,  | ||||
|                    n, n, n, | ||||
|                    uva, uvb, uvc ); | ||||
|     } | ||||
| 
 | ||||
|     public void AddQuad( | ||||
|       Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd, | ||||
|       Vector2 uva, Vector2 uvb, Vector2 uvc, Vector2 uvd | ||||
|     ) | ||||
|     { | ||||
| 
 | ||||
|       AddTriangle( va, vb, vc, uva, uvb, uvc ); | ||||
|       AddTriangle( vc, vd, va, uvc, uvd, uva ); | ||||
|     } | ||||
| 
 | ||||
|     public void AddTriangle( Vector3 va, Vector3 vb, Vector3 vc )     | ||||
|     { | ||||
|       var n  = Vector3.Up; | ||||
|       var uv = Vector2.Zero; | ||||
| 
 | ||||
|       AddTriangle( va, vb, vc,  n, n, n, uv, uv, uv ); | ||||
|     } | ||||
| 
 | ||||
|     public void AddQuad(  Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd  ) | ||||
|     { | ||||
|       AddTriangle( va, vb, vc ); | ||||
|       AddTriangle( vc, vd, va ); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public ArrayMesh Generate( Mesh.PrimitiveType type = Mesh.PrimitiveType.Triangles, ArrayMesh arrayMesh = null ) | ||||
|     { | ||||
|       if ( arrayMesh == null ) | ||||
|       { | ||||
|         arrayMesh = new ArrayMesh(); | ||||
|       } | ||||
| 
 | ||||
|       var surfaceArray = new Godot.Collections.Array(); | ||||
|       surfaceArray.Resize( (int) Mesh.ArrayType.Max ); | ||||
| 
 | ||||
|       if ( vertices != null ) | ||||
|       { | ||||
|         surfaceArray[ (int) Mesh.ArrayType.Vertex ] = vertices.ToArray(); | ||||
|       } | ||||
| 
 | ||||
|       if ( normals != null ) | ||||
|       { | ||||
|         surfaceArray[ (int) Mesh.ArrayType.Normal ] = normals.ToArray(); | ||||
|       } | ||||
| 
 | ||||
|       if ( uvs != null ) | ||||
|       { | ||||
|         surfaceArray[ (int) Mesh.ArrayType.TexUV ] = uvs.ToArray(); | ||||
|       } | ||||
| 
 | ||||
|       if ( uv2s != null ) | ||||
|       { | ||||
|         surfaceArray[ (int) Mesh.ArrayType.TexUV2 ] = uv2s.ToArray(); | ||||
|       } | ||||
| 
 | ||||
|       if ( colors != null ) | ||||
|       { | ||||
|         surfaceArray[ (int) Mesh.ArrayType.Color ] = colors.ToArray(); | ||||
|       } | ||||
| 
 | ||||
|       if ( indices != null ) | ||||
|       { | ||||
|         surfaceArray[ (int) Mesh.ArrayType.Index ] = indices.ToArray(); | ||||
|       } | ||||
| 
 | ||||
|       arrayMesh.AddSurfaceFromArrays( Mesh.PrimitiveType.Triangles, surfaceArray ); | ||||
| 
 | ||||
|       return arrayMesh; | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
| } | ||||
|  | @ -7,7 +7,7 @@ using System; | |||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
|    public abstract class RandomEngine | ||||
|   public abstract class RandomEngine | ||||
|   { | ||||
|     public abstract float Next(); | ||||
|          | ||||
|  | @ -208,6 +208,106 @@ namespace Rokojori | |||
|        | ||||
|       return list[ index ]; | ||||
|     } | ||||
| 
 | ||||
|     public T RemoveFrom<T>( List<T> list ) | ||||
|     { | ||||
|       if ( list.Count == 0 ) | ||||
|       { | ||||
|         return default ( T ); | ||||
|       } | ||||
| 
 | ||||
|       var index = this.IntegerExclusive( 0, list.Count ); | ||||
|        | ||||
|       var item = list[ index ]; | ||||
| 
 | ||||
|       list.RemoveAt( index ); | ||||
|       return item;   | ||||
|     } | ||||
| 
 | ||||
|     public List<T> RemoveMutlipleFrom<T>( List<T> list, int amount ) | ||||
|     { | ||||
|       if ( amount >= list.Count ) | ||||
|       { | ||||
|         return list; | ||||
|       } | ||||
|        | ||||
|       var items = new List<T>(); | ||||
| 
 | ||||
|       for ( int i = 0; i < amount; i++ ) | ||||
|       { | ||||
|         var itemIndex = this.IntegerExclusive( 0, list.Count ); | ||||
|         var item = list[ itemIndex ]; | ||||
|         list.RemoveAt( itemIndex ); | ||||
|         items.Add( item ); | ||||
|       }       | ||||
| 
 | ||||
|       return items; | ||||
|     } | ||||
| 
 | ||||
|     public T RemoveWeightedFrom<T>( List<T> list, List<float> weights ) | ||||
|     { | ||||
|       if ( list == null || list.Count == 0 ) | ||||
|       { | ||||
|         return default(T); | ||||
|       } | ||||
| 
 | ||||
|       if ( list.Count == 1 ) | ||||
|       { | ||||
|         return list[ 0 ]; | ||||
|       } | ||||
| 
 | ||||
|       var weightedSelection = RemoveMultipleWeightedFrom( list, weights, 1 ); | ||||
| 
 | ||||
| 
 | ||||
|       return weightedSelection[ 0 ]; | ||||
|     } | ||||
| 
 | ||||
|     public List<T> RemoveMultipleWeightedFrom<T>( List<T> list, List<float> weights, int amount ) | ||||
|     { | ||||
|       if ( amount >= list.Count ) | ||||
|       { | ||||
|         return list; | ||||
|       } | ||||
| 
 | ||||
|       var sumWeights = 0f; | ||||
| 
 | ||||
|       weights.ForEach( w => sumWeights += w ); | ||||
| 
 | ||||
|       var selection = new List<T>(); | ||||
| 
 | ||||
|       for ( int i = 0; i < amount; i++ ) | ||||
|       { | ||||
|         var number = Range( 0, sumWeights ); | ||||
| 
 | ||||
|         var index = _FindElementIndexWithWeights( weights, Range( 0, sumWeights ) ); | ||||
|         var element = list[ index ]; | ||||
|         var weight = weights[ index ]; | ||||
|         list.RemoveAt( index ); | ||||
|         sumWeights -= weight; | ||||
|         selection.Add( element ); | ||||
|       }  | ||||
| 
 | ||||
|       return selection; | ||||
|     } | ||||
| 
 | ||||
|     int _FindElementIndexWithWeights( List<float> weights, float value ) | ||||
|     { | ||||
|       var limit = 0f; | ||||
| 
 | ||||
|       for ( int i = 0; i < weights.Count; i++ ) | ||||
|       { | ||||
|         var before = limit; | ||||
|         limit += weights[ i ]; | ||||
| 
 | ||||
|         if ( before <= value && value < limit ) | ||||
|         { | ||||
|           return i; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       return weights.Count - 1; | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   public abstract class SeedableRandomEngine:RandomEngine | ||||
|  |  | |||
|  | @ -0,0 +1,10 @@ | |||
| 
 | ||||
| vec3 localToWorld( vec3 _VERTEX, mat4 _MODEL_MATRIX ) | ||||
| { | ||||
|   return ( _MODEL_MATRIX * vec4( _VERTEX, 1.0 ) ).xyz;   | ||||
| } | ||||
| 
 | ||||
| vec3 worldToLocal( vec3 _VERTEX, mat4 _MODEL_MATRIX ) | ||||
| { | ||||
|   return ( inverse( _MODEL_MATRIX ) * vec4( _VERTEX, 1.0 ) ).xyz;   | ||||
| } | ||||
|  | @ -36,6 +36,28 @@ namespace Rokojori | |||
|       return list.IndexOf( item ) != - 1; | ||||
|     } | ||||
| 
 | ||||
|     public static T RemoveAt<T>( List<T> list, int index ) | ||||
|     { | ||||
|       if ( list.Count == 0 || index < 0 ||  ( index > ( list.Count - 1 ) ) ) | ||||
|       {  | ||||
|         return default(T);  | ||||
|       } | ||||
| 
 | ||||
|       var first = list[ index ]; | ||||
|       list.RemoveAt( index ); | ||||
|       return first; | ||||
|     } | ||||
| 
 | ||||
|     public static T RemoveFirst<T>( List<T> list ) | ||||
|     { | ||||
|       return RemoveAt( list, 0 ); | ||||
|     } | ||||
| 
 | ||||
|     public static T RemoveLast<T>( List<T> list ) | ||||
|     { | ||||
|       return RemoveAt( list, list.Count - 1 ); | ||||
|     } | ||||
| 
 | ||||
|     public static T Pop<T>( List<T> list ) | ||||
|     { | ||||
|       if ( list.Count == 0 ){ return default(T); } | ||||
|  | @ -143,6 +165,23 @@ namespace Rokojori | |||
|       return copy; | ||||
|     } | ||||
| 
 | ||||
|     public static List<U> FilterAndMap<T,U>( List<T> list, Func<T,int,bool> filter, Func<T,U> map) | ||||
|     { | ||||
|       var mapped = new List<U>(); | ||||
|        | ||||
|       for ( int i = 0; i < list.Count; i++ ) | ||||
|       { | ||||
|         if ( ! filter( list[ i ], i ) ) | ||||
|         { | ||||
|           continue; | ||||
|         } | ||||
| 
 | ||||
|         mapped.Add( map( list[ i ] ) );  | ||||
|       } | ||||
| 
 | ||||
|       return mapped; | ||||
|     }  | ||||
| 
 | ||||
|     public static void Filter<T>( List<T> inputList, List<T> list, Func<T,int,bool> filter ) | ||||
|     {       | ||||
|       for ( int i = 0; i < inputList.Count; i++ ) | ||||
|  | @ -164,7 +203,7 @@ namespace Rokojori | |||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     public static List<T> Filter<T>( List<T> inputList, Func<T,bool> filter ) | ||||
|     {       | ||||
|       var list = new List<T>(); | ||||
|  | @ -198,6 +237,24 @@ namespace Rokojori | |||
|       ); | ||||
| 
 | ||||
|       return list; | ||||
|     }  | ||||
| 
 | ||||
|     public static void Add<T>( List<T> list, params T[] entries ) | ||||
|     { | ||||
|       list.AddRange( entries ); | ||||
|     } | ||||
| 
 | ||||
|     public static void Insert<T>( List<T> list, T item, int index ) | ||||
|     { | ||||
|       if ( index >= list.Count ) | ||||
|       { | ||||
|         list.Add( item ); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       index = index < 0 ? 0 : index; | ||||
| 
 | ||||
|       list.Insert( index, item ); | ||||
|     } | ||||
| 
 | ||||
|     public static T Find<T>( List<T> list, Func<T,bool> callback ) | ||||
|  |  | |||
|  | @ -0,0 +1,36 @@ | |||
| using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System; | ||||
| using System.Reflection; | ||||
| using System.Text.RegularExpressions; | ||||
| 
 | ||||
| namespace Rokojori | ||||
| { | ||||
|   public class Safe | ||||
|   { | ||||
|     static readonly int maxWhileIterations = 1000 * 1000; | ||||
| 
 | ||||
|     public static void While( Func<bool> condition, Action action, Action onTooManyIterations = null ) | ||||
|     { | ||||
|       var it = 0; | ||||
| 
 | ||||
|       while ( it < Safe.maxWhileIterations && condition() ) | ||||
|       { | ||||
|         action(); | ||||
|         it++; | ||||
|       } | ||||
| 
 | ||||
|       if ( it >= Safe.maxWhileIterations ) | ||||
|       { | ||||
|         RJLog.LogWithFullTrace( "Loop with too many iterations" ); | ||||
| 
 | ||||
|         if ( onTooManyIterations != null ) | ||||
|         { | ||||
|           onTooManyIterations(); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -67,13 +67,13 @@ namespace Rokojori | |||
|       var maxWidth = 0f; | ||||
|       var maxHeight = 0f; | ||||
| 
 | ||||
|       if ( UINumber.IsNullOrNone( region.width ) ) | ||||
|       if ( UINumber.IsNullOrNone( UIStyle.Width( region ) ) ) | ||||
|       { | ||||
|         lines.ForEach( l => { maxWidth = Mathf.Max( maxWidth, l.maxX ); } ); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         maxWidth = UINumber.Compute( region, region.width );  | ||||
|         maxWidth = UINumber.Compute( region, UIStyle.Width( region ) );  | ||||
|       } | ||||
| 
 | ||||
|       if ( lines.Count > 0 ) | ||||
|  | @ -81,12 +81,12 @@ namespace Rokojori | |||
|         maxHeight = lines[ lines.Count - 1 ].maxY; | ||||
|       }   | ||||
| 
 | ||||
|       var margin     = UINumber.Compute( region, region.margin, 0 ); | ||||
|       var marginLeft = margin + UINumber.Compute( region, region.marginLeft, 0 ); | ||||
|       var marginTop  = margin + UINumber.Compute( region, region.marginTop, 0 );  | ||||
|       var margin     = UINumber.Compute( region, UIStyle.Margin( region ), 0 ); | ||||
|       var marginLeft = margin + UINumber.Compute( region, UIStyle.MarginLeft( region ), 0 ); | ||||
|       var marginTop  = margin + UINumber.Compute( region, UIStyle.MarginTop( region ), 0 );  | ||||
| 
 | ||||
|       var marginRight = margin + UINumber.Compute( region, region.marginRight, 0 ); | ||||
|       var marginBottom = margin + UINumber.Compute( region, region.marginBottom, 0 );  | ||||
|       var marginRight = margin + UINumber.Compute( region, UIStyle.MarginRight( region ), 0 ); | ||||
|       var marginBottom = margin + UINumber.Compute( region, UIStyle.MarginBottom( region ), 0 );  | ||||
| 
 | ||||
| 
 | ||||
|       var marginOffset = new Vector2( marginLeft, marginTop ); | ||||
|  | @ -98,46 +98,38 @@ namespace Rokojori | |||
| 
 | ||||
|       region.Size = new Vector2( maxWidth + horizontalMargins, maxHeight + verticalMargins ); | ||||
| 
 | ||||
|       if ( region.position == UIPosition.Parent_Anchor ) | ||||
|       if ( UIStyle.Position( region ) == UIPosition.Parent_Anchor ) | ||||
|       { | ||||
|         var p = NodesWalker.Get().Parent( region ) as Control; | ||||
| 
 | ||||
|         if ( p != null ) | ||||
|         { | ||||
|           var pWidth = UILayouting.GetWidth( p ); | ||||
|           var pHeight = UILayouting.GetHeight( p );    | ||||
|            | ||||
|           var x = p.Position.X; | ||||
|           var y = p.Position.Y; | ||||
| 
 | ||||
| 
 | ||||
|           if ( ! UINumber.IsNullOrNone( region.left )) | ||||
|           { | ||||
|             var left  = UINumber.Compute( region, region.left, 0 ); | ||||
|             x = left; | ||||
|           } | ||||
|           else if ( ! UINumber.IsNullOrNone( region.right ) ) | ||||
|           { | ||||
|             var right  = UINumber.Compute( region, region.right, 0 ); | ||||
|             x = ( pWidth - UILayouting.GetWidth( region ) ) - right; | ||||
|           } | ||||
| 
 | ||||
|           UILayouting.SetPosition( region, new Vector2( x, y ) ); | ||||
| 
 | ||||
|         } | ||||
|          | ||||
|         UILayouting.SetPositionInParentAnchor( region ); | ||||
|       } | ||||
| 
 | ||||
|       Nodes.ForEachDirectChild<Control>( region, | ||||
|         child => | ||||
|         { | ||||
|            | ||||
|           var styleContainer = child as UIStylePropertyContainer; | ||||
| 
 | ||||
|           if ( styleContainer == null || UIStyle.Position( styleContainer ) != UIPosition.Parent_Anchor ) | ||||
|           { | ||||
|             return; | ||||
|           } | ||||
| 
 | ||||
|           UILayouting.UpdateChild( child ); | ||||
|           UILayouting.SetPositionInParentAnchor( styleContainer ); | ||||
|            | ||||
|         } | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     static List<Line> CreateLines( UIRegion region ) | ||||
|     { | ||||
|       var x = 0f; | ||||
|       var width = UINumber.Compute( region, region.width, 100000000f ); | ||||
|       var width = UINumber.Compute( region, UIStyle.Width( region ), 100000000f ); | ||||
| 
 | ||||
|       var lines = new List<Line>(); | ||||
|       var currentLine = new Line(); | ||||
| 
 | ||||
|       var elementSpacing = UINumber.Compute( region, region.elementSpacing, 0f ); | ||||
|       var elementSpacing = UINumber.Compute( region, UIStyle.ElementSpacing( region ), 0f ); | ||||
| 
 | ||||
|       Nodes.ForEachDirectChild<Control>( region, c => UILayouting.UpdateChild( c ) ); | ||||
|        | ||||
|  | @ -146,6 +138,13 @@ namespace Rokojori | |||
|         child => | ||||
|         { | ||||
|            | ||||
|           var styleContainer = child as UIStylePropertyContainer; | ||||
| 
 | ||||
|           if ( styleContainer != null && UIStyle.Position( styleContainer ) == UIPosition.Parent_Anchor ) | ||||
|           { | ||||
|             return; | ||||
|           } | ||||
|            | ||||
|           var cWidth  = UILayouting.GetWidth( child ); | ||||
|           var cHeight = UILayouting.GetHeight( child ); | ||||
| 
 | ||||
|  | @ -193,13 +192,13 @@ namespace Rokojori | |||
| 
 | ||||
|       lines.ForEach(  line => AdjustVerticalAlignment( region, line, verticalAlignment ) ); | ||||
| 
 | ||||
|       if ( UINumber.IsNullOrNone( region.width ) ) | ||||
|       if ( UINumber.IsNullOrNone( UIStyle.Width( region ) ) ) | ||||
|       { | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       var horizontalAlignment = UINumber.Compute( region, region.horizontalAlignment, 0.5f, 1 ); | ||||
|       var maxWidth = UINumber.Compute( region, region.width, 0 ); | ||||
|       var maxWidth = UINumber.Compute( region, UIStyle.Width( region ), 0 ); | ||||
| 
 | ||||
|       lines.ForEach( line => AdjustHorizontalAlignment( region, line, horizontalAlignment, maxWidth ) ); | ||||
| 
 | ||||
|  |  | |||
|  | @ -40,6 +40,45 @@ namespace Rokojori | |||
|       UILayouting.UpdatePivot( control ); | ||||
|     } | ||||
| 
 | ||||
|     public static void SetPositionInParentAnchor( UIStylePropertyContainer region ) | ||||
|     { | ||||
|       var control = (Control) region; | ||||
|       var p = NodesWalker.Get().Parent( control ) as Control; | ||||
|        | ||||
|       var pWidth  = p == null ? UI.GetWindowWidth( control ) : UILayouting.GetWidth( p ); | ||||
|       var pHeight = p == null ? UI.GetWindowHeight( control ) : UILayouting.GetHeight( p );    | ||||
|        | ||||
|       var x = p.Position.X; | ||||
|       var y = p.Position.Y; | ||||
| 
 | ||||
| 
 | ||||
|       if ( ! UINumber.IsNullOrNone( UIStyle.Left( region ) )) | ||||
|       { | ||||
|         var left  = UINumber.Compute( control, UIStyle.Left( region ), 0 ); | ||||
|         x = left; | ||||
|       } | ||||
|       else if ( ! UINumber.IsNullOrNone( UIStyle.Right( region ) ) ) | ||||
|       { | ||||
|         var right  = UINumber.Compute( control, UIStyle.Right( region ), 0 ); | ||||
|         x = ( pWidth - UILayouting.GetWidth( control ) ) - right; | ||||
|       } | ||||
| 
 | ||||
|       if ( ! UINumber.IsNullOrNone( UIStyle.Top( region ) )) | ||||
|       { | ||||
|         var top  = UINumber.Compute( control, UIStyle.Top( region ), 0 ); | ||||
|         y = top; | ||||
|       } | ||||
|       else if ( ! UINumber.IsNullOrNone( UIStyle.Bottom( region ) ) ) | ||||
|       { | ||||
|         var bottom  = UINumber.Compute( control, UIStyle.Bottom( region ), 0 ); | ||||
|         y = ( pHeight - UILayouting.GetHeight( control ) ) - bottom; | ||||
|       } | ||||
| 
 | ||||
|       UILayouting.SetPosition( control, new Vector2( x, y ) ); | ||||
| 
 | ||||
|        | ||||
|     } | ||||
| 
 | ||||
|     public static void UpdatePivot( Control c ) | ||||
|     { | ||||
|       if ( ! ( c is UIImage || c is UIRegion || c is UIText ) ) | ||||
|  | @ -49,8 +88,8 @@ namespace Rokojori | |||
| 
 | ||||
|       var container = c as UIStylePropertyContainer; | ||||
| 
 | ||||
|       var pivotX  = UINumber.Compute( c, UIStyle.PivotX( container ), 0, c.Size.X ); | ||||
|       var pivotY  = UINumber.Compute( c, UIStyle.PivotY( container ), 0, c.Size.Y ); | ||||
|       var pivotX  = UINumber.Compute( c, UIStyle.PivotX( container ), 0.5f * c.Size.X, c.Size.X ); | ||||
|       var pivotY  = UINumber.Compute( c, UIStyle.PivotY( container ), 0.5f * c.Size.Y, c.Size.Y ); | ||||
| 
 | ||||
|       c.PivotOffset = new Vector2( pivotX, pivotY ); | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,9 @@ namespace Rokojori | |||
|   [GlobalClass] | ||||
|   public partial class UIImage:TextureRect, UIStylePropertyContainer | ||||
|   {  | ||||
|     [Export] | ||||
|     public UIStyle parentStyle; | ||||
| 
 | ||||
|     [ExportCategory("Size & Margins")] | ||||
|     [Export] | ||||
|     public UINumber width; | ||||
|  | @ -60,6 +63,16 @@ namespace Rokojori | |||
|     public UINumber scaleY; | ||||
| 
 | ||||
| 
 | ||||
|     public UIStyle GetUIStyleParent() | ||||
|     { | ||||
|       return parentStyle; | ||||
|     } | ||||
| 
 | ||||
|     public UIPosition GetUIPosition() | ||||
|     { | ||||
|       return position; | ||||
|     } | ||||
| 
 | ||||
|     public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property ) | ||||
|     { | ||||
|       switch ( property ) | ||||
|  |  | |||
|  | @ -8,9 +8,9 @@ namespace Rokojori | |||
|   public partial class UIRegion : Control, UIStylePropertyContainer | ||||
|   {    | ||||
|     [Export] | ||||
|     public UIStyle parent; | ||||
|     public UIStyle parentStyle; | ||||
| 
 | ||||
|     [ExportCategory("Layout")] | ||||
|     [ExportCategory( "Layout" )] | ||||
|     [Export] | ||||
|     public UILayout layout;         | ||||
| 
 | ||||
|  | @ -25,7 +25,7 @@ namespace Rokojori | |||
|     public UINumber lineSpacing; | ||||
| 
 | ||||
|      | ||||
|     [ExportCategory("Size & Margins")] | ||||
|     [ExportCategory( "Size & Margins" )] | ||||
|     [Export] | ||||
|     public UINumber width; | ||||
|     [Export] | ||||
|  | @ -44,7 +44,27 @@ namespace Rokojori | |||
|     [Export]  | ||||
|     public UINumber marginBottom; | ||||
| 
 | ||||
|     [ExportCategory("Position")] | ||||
|     [ExportCategory( "Font" )] | ||||
|     [Export] | ||||
|     public Font font; | ||||
|     [Export] | ||||
|     public UINumber fontSize; | ||||
|     [Export] | ||||
|     public UIColor fontColor; | ||||
| 
 | ||||
|     [Export] | ||||
|     public UINumber outlineSize; | ||||
|     [Export] | ||||
|     public UIColor outlineColor; | ||||
| 
 | ||||
|     [Export] | ||||
|     public UINumber shadowSize; | ||||
|     [Export] | ||||
|     public UIColor shadowColor; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     [ExportCategory( "Position" )] | ||||
|     [Export] | ||||
|     public UIPosition position; | ||||
|     [Export] | ||||
|  | @ -57,6 +77,16 @@ namespace Rokojori | |||
|     public UINumber bottom; | ||||
| 
 | ||||
| 
 | ||||
|     public UIStyle GetUIStyleParent() | ||||
|     { | ||||
|       return parentStyle; | ||||
|     } | ||||
| 
 | ||||
|     public UIPosition GetUIPosition() | ||||
|     { | ||||
|       return position; | ||||
|     } | ||||
| 
 | ||||
|     public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property ) | ||||
|     { | ||||
|       switch ( property ) | ||||
|  | @ -69,6 +99,10 @@ namespace Rokojori | |||
|         case UIStyleNumberProperty.Width:  return width; | ||||
|         case UIStyleNumberProperty.Height: return height; | ||||
| 
 | ||||
|          | ||||
|         case UIStyleNumberProperty.ElementSpacing: return elementSpacing; | ||||
|         case UIStyleNumberProperty.LineSpacing:    return lineSpacing; | ||||
| 
 | ||||
|         case UIStyleNumberProperty.Margin:       return margin; | ||||
| 
 | ||||
|         case UIStyleNumberProperty.MarginLeft:   return marginLeft; | ||||
|  |  | |||
|  | @ -8,6 +8,12 @@ namespace Rokojori | |||
|   [GlobalClass] | ||||
|   public partial class UIText:Label,UIStylePropertyContainer | ||||
|   { | ||||
|     [Export] | ||||
|     public UIStyle parentStyle; | ||||
| 
 | ||||
|     [Export] | ||||
|     public UINumber fontSize; | ||||
| 
 | ||||
|     [ExportCategory("Size & Margins")] | ||||
|     [Export] | ||||
|     public UINumber width; | ||||
|  | @ -59,6 +65,15 @@ namespace Rokojori | |||
|     [Export] | ||||
|     public UINumber scaleY; | ||||
| 
 | ||||
|     public UIStyle GetUIStyleParent() | ||||
|     { | ||||
|       return parentStyle; | ||||
|     } | ||||
| 
 | ||||
|     public UIPosition GetUIPosition() | ||||
|     { | ||||
|       return position; | ||||
|     } | ||||
| 
 | ||||
|     public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property ) | ||||
|     { | ||||
|  |  | |||
|  | @ -0,0 +1,15 @@ | |||
| 
 | ||||
| using Godot; | ||||
| using Rokojori; | ||||
|   | ||||
| namespace Rokojori | ||||
| {  | ||||
| 
 | ||||
|   [Tool] | ||||
|   [GlobalClass]  | ||||
|   public partial class UIColor : Resource | ||||
|   {  | ||||
|     [Export] | ||||
|     public Color color; | ||||
|   } | ||||
| } | ||||
|  | @ -34,6 +34,7 @@ namespace Rokojori | |||
|       return number.IsNone; | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     public static float Compute( Control control, UINumber number, float alternative = 0, float relative = 100 ) | ||||
|     { | ||||
|       if ( number == null || control == null || number.IsNone ) | ||||
|  | @ -41,19 +42,9 @@ namespace Rokojori | |||
|         return alternative; | ||||
|       } | ||||
| 
 | ||||
|       var width = 0; | ||||
|       var height = 0; | ||||
|       var width  = UI.GetWindowWidth( control ); | ||||
|       var height = UI.GetWindowHeight( control ); | ||||
| 
 | ||||
|       if ( Engine.IsEditorHint() ) | ||||
|       { | ||||
|         width  = ProjectSettings.GetSetting( "display/window/size/viewport_width" ).AsInt32(); | ||||
|         height = ProjectSettings.GetSetting( "display/window/size/viewport_height" ).AsInt32(); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         width  = control.GetWindow().Size.X; | ||||
|         height = control.GetWindow().Size.Y; | ||||
|       } | ||||
| 
 | ||||
|       return Compute( control, number, width, height, relative ); | ||||
|        | ||||
|  | @ -75,7 +66,7 @@ namespace Rokojori | |||
| 
 | ||||
|       if ( _ui == null ) | ||||
|       { | ||||
|        // _ui = NodesWalker.Get().GetParent( control, n => n is UI ) as UI; | ||||
|         _ui = NodesWalker.Get().GetInParents( control, n => n is UI ) as UI; | ||||
|       } | ||||
| 
 | ||||
|       switch ( number.unit ) | ||||
|  | @ -95,6 +86,18 @@ namespace Rokojori | |||
|           return number.value * height / 100f; | ||||
|         } | ||||
| 
 | ||||
|         case "pw": | ||||
|         { | ||||
|           var parent = control.GetParent<Control>(); | ||||
|           return number.value / 100f * ( parent == null ?  width : parent.Size.X ); | ||||
|         } | ||||
| 
 | ||||
|         case "ph": | ||||
|         { | ||||
|           var parent = control.GetParent<Control>(); | ||||
|           return number.value / 100f * ( parent == null ?  height : parent.Size.Y ); | ||||
|         } | ||||
| 
 | ||||
|         case "px": case "": | ||||
|         { | ||||
|           return number.value; | ||||
|  | @ -110,17 +113,25 @@ namespace Rokojori | |||
| 
 | ||||
| 
 | ||||
|       var expressionText = number.unit == null ? "" : RegexUtility.Replace( number.unit, "%", " * relative " );  | ||||
|       var parseResult = expression.Parse( expressionText, new string[]{ "em","vw", "vh", "px", "relative", "value" } ); | ||||
|       var parseResult = expression.Parse( expressionText,  | ||||
|         new string[] | ||||
|         {  | ||||
|           "em","vw", "vh", "pw", "ph", "px", "relative", "value" }  | ||||
|         ); | ||||
| 
 | ||||
|       if ( Error.Ok != parseResult ) | ||||
|       { | ||||
|         return 0; | ||||
|       } | ||||
| 
 | ||||
|       var parentControl = control.GetParent<Control>(); | ||||
| 
 | ||||
|       var inputs = new Godot.Collections.Array(); | ||||
|       inputs.Add( em() ); | ||||
|       inputs.Add( width / 100f ); | ||||
|       inputs.Add( height / 100f ); | ||||
|       inputs.Add( ( parentControl == null ? width : parentControl.Size.X ) / 100f ); | ||||
|       inputs.Add( ( parentControl == null ? height : parentControl.Size.Y ) / 100f ); | ||||
|       inputs.Add( 1 );       | ||||
|       inputs.Add( relative / 100f ); | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,6 +6,7 @@ namespace Rokojori | |||
| {  | ||||
|   public enum UIPosition | ||||
|   { | ||||
|     ___, | ||||
|     From_Layout, | ||||
|     Parent_Anchor | ||||
|   } | ||||
|  |  | |||
|  | @ -7,106 +7,236 @@ namespace Rokojori | |||
| 
 | ||||
|   [Tool] | ||||
|   [GlobalClass]  | ||||
|   public partial class UIStyle:Resource | ||||
|   public partial class UIStyle:Resource, UIStylePropertyContainer | ||||
|   { | ||||
|     [Export] | ||||
|     public UIStyle parent; | ||||
|    | ||||
|     [Export] | ||||
|     public UILayout layoutType; | ||||
|     public UIStyle parentStyle; | ||||
| 
 | ||||
|     [ExportCategory("Width")] | ||||
|     [ExportCategory( "Layout" )] | ||||
|     [Export] | ||||
|     public float widthValue = 1; | ||||
|     [Export] | ||||
|     public string widthUnit = "vw"; | ||||
|     public UILayout layout;         | ||||
| 
 | ||||
|     [ExportCategory("Height")] | ||||
|     [Export] | ||||
|     public float heightValue = 1; | ||||
|     public UINumber horizontalAlignment; | ||||
|     [Export] | ||||
|     public string heightUnit = "vw"; | ||||
|     public UINumber verticalAlignment; | ||||
| 
 | ||||
|     [ExportCategory("LineSpacing")] | ||||
|     [Export] | ||||
|     public float lineSpacingValue = 1; | ||||
|     public UINumber elementSpacing; | ||||
|     [Export] | ||||
|     public string ineSpacingtUnit = "vw"; | ||||
|     public UINumber lineSpacing; | ||||
| 
 | ||||
|      | ||||
|     [ExportCategory( "Size & Margins" )] | ||||
|     [Export] | ||||
|     public UINumber width; | ||||
|     [Export] | ||||
|     public UINumber height; | ||||
| 
 | ||||
| 
 | ||||
|     [Export]  | ||||
|     public UINumber margin; | ||||
| 
 | ||||
|     [Export]  | ||||
|     public UINumber marginLeft; | ||||
|     [Export]  | ||||
|     public UINumber marginTop; | ||||
|     [Export]  | ||||
|     public UINumber marginRight; | ||||
|     [Export]  | ||||
|     public UINumber marginBottom; | ||||
| 
 | ||||
|     [ExportCategory( "Font" )] | ||||
|     [Export] | ||||
|     public Font font; | ||||
|     [Export] | ||||
|     public UINumber fontSize; | ||||
|     [Export] | ||||
|     public UIColor fontColor; | ||||
| 
 | ||||
|     [Export] | ||||
|     public UINumber outlineSize; | ||||
|     [Export] | ||||
|     public UIColor outlineColor; | ||||
| 
 | ||||
|     [Export] | ||||
|     public UINumber shadowSize; | ||||
|     [Export] | ||||
|     public UIColor shadowColor; | ||||
| 
 | ||||
|     [ExportCategory( "Position" )] | ||||
|     [Export] | ||||
|     public UIPosition position; | ||||
|     [Export] | ||||
|     public UINumber left; | ||||
|     [Export] | ||||
|     public UINumber top; | ||||
|     [Export] | ||||
|     public UINumber right; | ||||
|     [Export] | ||||
|     public UINumber bottom; | ||||
|     | ||||
|     public UIStyle GetUIStyleParent() | ||||
|     { | ||||
|       return parentStyle; | ||||
|     } | ||||
| 
 | ||||
|     public UIPosition GetUIPosition() | ||||
|     { | ||||
|       return position; | ||||
|     } | ||||
| 
 | ||||
|     public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property ) | ||||
|     { | ||||
|       switch ( property ) | ||||
|       { | ||||
|         case UIStyleNumberProperty.Left:   return left; | ||||
|         case UIStyleNumberProperty.Right:  return right; | ||||
|         case UIStyleNumberProperty.Top:    return top; | ||||
|         case UIStyleNumberProperty.Bottom: return bottom; | ||||
| 
 | ||||
|         case UIStyleNumberProperty.ElementSpacing: return elementSpacing; | ||||
|         case UIStyleNumberProperty.LineSpacing:    return lineSpacing; | ||||
| 
 | ||||
| 
 | ||||
|         case UIStyleNumberProperty.Width:  return width; | ||||
|         case UIStyleNumberProperty.Height: return height; | ||||
| 
 | ||||
|         case UIStyleNumberProperty.Margin:       return margin; | ||||
| 
 | ||||
|         case UIStyleNumberProperty.MarginLeft:   return marginLeft; | ||||
|         case UIStyleNumberProperty.MarginRight:  return marginRight; | ||||
|         case UIStyleNumberProperty.MarginTop:    return marginTop; | ||||
|         case UIStyleNumberProperty.MarginBottom: return marginBottom; | ||||
|       } | ||||
| 
 | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber GetReferenceableNumberProperty( UIStylePropertyContainer container, UIStyleNumberProperty property ) | ||||
|     { | ||||
|       if ( container == null ) | ||||
|       { | ||||
|         return null; | ||||
|       } | ||||
| 
 | ||||
|       var ownProperty = container.GetUIStyleNumberProperty( property ); | ||||
| 
 | ||||
|       if ( ownProperty != null ) | ||||
|       { | ||||
|         return ownProperty; | ||||
|       } | ||||
| 
 | ||||
|       var style = container.GetUIStyleParent(); | ||||
| 
 | ||||
|       return GetReferenceableNumberProperty( style, property ); | ||||
|     }  | ||||
| 
 | ||||
|     public static UIPosition Position( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       var ownProperty = container.GetUIPosition(); | ||||
| 
 | ||||
|       if ( ownProperty != UIPosition.___ ) | ||||
|       { | ||||
|         return ownProperty; | ||||
|       } | ||||
| 
 | ||||
|       return container.GetUIPosition(); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber Width( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Width ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber Height( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Height ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber Left( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Left ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Left ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber Right( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Right ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Right ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber Top( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Top ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Top ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber Bottom( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Bottom ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Bottom ); | ||||
|     } | ||||
|      | ||||
|     public static UINumber Margin( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Margin ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Margin ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber MarginLeft( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginLeft ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginLeft ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber MarginRight( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginRight ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginRight ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber MarginTop( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginTop ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginTop ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber MarginBottom( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginBottom ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginBottom ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber PivotX( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.PivotX ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.PivotX ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber PivotY( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.PivotY ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.PivotY ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber Rotation( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Rotation ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Rotation ); | ||||
|     } | ||||
|   | ||||
|     public static UINumber Scale( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Scale ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Scale ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber ScaleX( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.ScaleX ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.ScaleX ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber ScaleY( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return container.GetUIStyleNumberProperty( UIStyleNumberProperty.ScaleY ); | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.ScaleY ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber ElementSpacing( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.ElementSpacing ); | ||||
|     } | ||||
| 
 | ||||
|     public static UINumber LineSpacing( UIStylePropertyContainer container ) | ||||
|     { | ||||
|       return GetReferenceableNumberProperty( container, UIStyleNumberProperty.LineSpacing ); | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
|  |  | |||
|  | @ -14,6 +14,9 @@ namespace Rokojori | |||
|     Width, | ||||
|     Height, | ||||
| 
 | ||||
|     ElementSpacing, | ||||
|     LineSpacing, | ||||
| 
 | ||||
|     Margin, | ||||
|     MarginLeft, | ||||
|     MarginRight, | ||||
|  | @ -27,6 +30,17 @@ namespace Rokojori | |||
| 
 | ||||
|     Scale, | ||||
|     ScaleX, | ||||
|     ScaleY | ||||
|     ScaleY, | ||||
| 
 | ||||
|     FontSize, | ||||
|     FontOutlineSize, | ||||
|     FontShadowSize | ||||
|   } | ||||
| 
 | ||||
|   public enum UIStyleColorProperty | ||||
|   { | ||||
|     FontColor, | ||||
|     FontOutlineColor, | ||||
|     FontShadowColor | ||||
|   } | ||||
| } | ||||
|  | @ -6,6 +6,9 @@ namespace Rokojori | |||
| {  | ||||
|   public interface UIStylePropertyContainer | ||||
|   { | ||||
|     UIStyle GetUIStyleParent(); | ||||
| 
 | ||||
|     UIPosition GetUIPosition(); | ||||
|     UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property ); | ||||
|   } | ||||
| } | ||||
|  | @ -29,7 +29,7 @@ namespace Rokojori | |||
|       UpdateUIElements(); | ||||
|     } | ||||
| 
 | ||||
|          | ||||
| 
 | ||||
| 
 | ||||
|     void UpdateFontSize() | ||||
|     { | ||||
|  | @ -53,6 +53,30 @@ namespace Rokojori | |||
|       Nodes.ForEachDirectChild<UIRegion>( this, r => r.Layout() ); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public static float GetWindowWidth( Control control ) | ||||
|     { | ||||
|       if ( Engine.IsEditorHint() ) | ||||
|       { | ||||
|         return ProjectSettings.GetSetting( "display/window/size/viewport_width" ).AsInt32(); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         return control.GetWindow().Size.X; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     public static float GetWindowHeight( Control control ) | ||||
|     { | ||||
|       if ( Engine.IsEditorHint() ) | ||||
|       { | ||||
|         return ProjectSettings.GetSetting( "display/window/size/viewport_height" ).AsInt32(); | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|         return control.GetWindow().Size.Y; | ||||
|       } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|   } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Josef
						Josef