Math/Procederul Updates
This commit is contained in:
parent
575431f868
commit
fed16cb75c
|
@ -0,0 +1,83 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
version="1.1"
|
||||
id="svg42222"
|
||||
sodipodi:docname="Scatterer.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs42226" />
|
||||
<sodipodi:namedview
|
||||
id="namedview42224"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="14.75"
|
||||
inkscape:cx="14.305085"
|
||||
inkscape:cy="10.745763"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg42222" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path43509"
|
||||
cx="6.5593214"
|
||||
cy="10.899628"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle43563"
|
||||
cx="2.8305085"
|
||||
cy="12.933526"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle46711"
|
||||
cx="10.355931"
|
||||
cy="13.103018"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle46713"
|
||||
cx="13.237288"
|
||||
cy="10.391153"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle46715"
|
||||
cx="9.7118645"
|
||||
cy="7.5436959"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle46717"
|
||||
cx="3"
|
||||
cy="7.3742042"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle46719"
|
||||
cx="6.3559322"
|
||||
cy="3.3742044"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle46721"
|
||||
cx="12.322034"
|
||||
cy="3.3064077"
|
||||
r="1.9322034" />
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
|
@ -0,0 +1,37 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://clm1p530y0sh0"
|
||||
path="res://.godot/imported/Scatterer.svg-faa0f406c786220743edbcf86085b917.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Scripts/Rokojori/Rokojori-Action-Library/Icons/Scatterer.svg"
|
||||
dest_files=["res://.godot/imported/Scatterer.svg-faa0f406c786220743edbcf86085b917.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
version="1.1"
|
||||
id="svg42222"
|
||||
sodipodi:docname="Spline.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs42226" />
|
||||
<sodipodi:namedview
|
||||
id="namedview42224"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="20.85965"
|
||||
inkscape:cx="15.532379"
|
||||
inkscape:cy="15.796046"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg42222" />
|
||||
<path
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#fc7f7f;stroke-width:2;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
d="M 12.047939,3.2118215 C 10.778939,2.3699272 5.6943781,1.9062831 4.5423729,2.9152542 3.5900977,3.7492939 3.3064257,5.5473527 4.0263787,6.6776739 4.8897493,8.0331597 10.029541,8.1436155 12.186233,8.798812 c 2.069946,0.6288435 1.37427,2.899163 0.534562,3.913053 -1.676235,2.02394 -6.6161891,1.149842 -7.8733374,0.406779"
|
||||
id="path42345"
|
||||
sodipodi:nodetypes="csssac" />
|
||||
<circle
|
||||
style="opacity:1;fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="path43509"
|
||||
cx="12.881356"
|
||||
cy="3.4915257"
|
||||
r="1.9322034" />
|
||||
<circle
|
||||
style="opacity:1;fill:#fc7f7f;fill-opacity:1;stroke:none;stroke-width:4.22222;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="circle43563"
|
||||
cx="3.3559334"
|
||||
cy="12.169491"
|
||||
r="1.9322034" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1,37 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://c4t5wy2e8guge"
|
||||
path="res://.godot/imported/Spline.svg-24ecac2761c76806ec867265b5304b23.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Scripts/Rokojori/Rokojori-Action-Library/Icons/Spline.svg"
|
||||
dest_files=["res://.godot/imported/Spline.svg-24ecac2761c76806ec867265b5304b23.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
|
@ -0,0 +1,56 @@
|
|||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum ColorBlendModeType
|
||||
{
|
||||
Alpha,
|
||||
Add,
|
||||
Multiply,
|
||||
Replace
|
||||
}
|
||||
|
||||
public class ColorBlendMode
|
||||
{
|
||||
public static Color Blend( ColorBlendModeType type, Color bottom, Color top )
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
case ColorBlendModeType.Alpha: return Alpha( bottom, top );
|
||||
case ColorBlendModeType.Multiply: return Multiply( bottom, top );
|
||||
case ColorBlendModeType.Add: return Add( bottom, top );
|
||||
case ColorBlendModeType.Replace: return Replace( bottom, top );
|
||||
}
|
||||
|
||||
return new Color( 1, 1, 1, 1 );
|
||||
}
|
||||
|
||||
public static Color Alpha( Color bottom, Color top )
|
||||
{
|
||||
var a = top.A + bottom.A * ( 1f - top.A );
|
||||
|
||||
var colorBottom = ColorX.RGB( bottom );
|
||||
var colorTop = ColorX.RGB( top );
|
||||
|
||||
var colorRGB = ( colorTop * top.A + colorBottom * bottom.A * ( 1f - top.A ) ) / a;
|
||||
|
||||
return ColorX.Create( colorRGB, a );
|
||||
}
|
||||
|
||||
public static Color Multiply( Color bottom, Color top )
|
||||
{
|
||||
return bottom * top;
|
||||
}
|
||||
|
||||
public static Color Add( Color bottom, Color top )
|
||||
{
|
||||
return bottom + top;
|
||||
}
|
||||
|
||||
public static Color Replace( Color bottom, Color top )
|
||||
{
|
||||
return top;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class ColorX
|
||||
{
|
||||
public static Color Lerp( Color a, Color b, float amount )
|
||||
{
|
||||
return a.Lerp( b, amount );
|
||||
}
|
||||
|
||||
public static Vector3 RGB( Color c )
|
||||
{
|
||||
return new Vector3( c.R, c.G, c.B );
|
||||
}
|
||||
|
||||
public static Vector2 RA( Color c )
|
||||
{
|
||||
return new Vector2( c.R, c.A);
|
||||
}
|
||||
|
||||
public static Color Create( Vector3 rgb, float a )
|
||||
{
|
||||
return new Color( rgb.X, rgb.Y, rgb.Z, a );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -75,6 +75,8 @@ namespace Rokojori
|
|||
ForEach<T>( root, callback );
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static List<T> AllInScene<T>( Func<T,bool> filter = null) where T:class
|
||||
{
|
||||
var list = new List<T>();
|
||||
|
@ -144,6 +146,35 @@ namespace Rokojori
|
|||
return GetDirectChild<T>( parent );
|
||||
}
|
||||
|
||||
public static void RemoveAndDelete( Node node )
|
||||
{
|
||||
var parent = node.GetParent();
|
||||
|
||||
if ( parent != null )
|
||||
{
|
||||
parent.RemoveChild( node );
|
||||
}
|
||||
|
||||
node.QueueFree();
|
||||
}
|
||||
|
||||
public static void RemoveAndDeleteChildren( Node parent, bool includeInternal = false )
|
||||
{
|
||||
if ( parent == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var numChildren = parent.GetChildCount( includeInternal );
|
||||
|
||||
for ( int i = numChildren - 1; i >= 0; i-- )
|
||||
{
|
||||
var node = parent.GetChild( i, includeInternal );
|
||||
parent.RemoveChild( node );
|
||||
node.QueueFree();
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetDirectChild<T>( Node parent ) where T:Node
|
||||
{
|
||||
if ( parent == null )
|
||||
|
@ -219,6 +250,40 @@ namespace Rokojori
|
|||
}
|
||||
}
|
||||
|
||||
public static List<U> MapDirectChildren<T,U>( Node parent, System.Func<T,U> mapper ) where T:Node
|
||||
{
|
||||
var list = new List<U>();
|
||||
|
||||
ForEachDirectChild<T>( parent, c => list.Add( mapper( c ) ) );
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static int TypeIndex<T>( Node parent, T child ) where T:Node
|
||||
{
|
||||
var counter = 0;
|
||||
|
||||
var numChildren = parent.GetChildCount();
|
||||
|
||||
for ( int i = 0; i < numChildren; i++ )
|
||||
{
|
||||
var node = parent.GetChild( i );
|
||||
|
||||
if ( node is T )
|
||||
{
|
||||
if ( node == child )
|
||||
{
|
||||
return counter;
|
||||
}
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static NodesWalker nodesWalker = new NodesWalker();
|
||||
|
||||
public static T GetAnyChild<T>( Node parent ) where T:Node
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Box2
|
||||
{
|
||||
public Vector2 min = Vector2.Zero;
|
||||
public Vector2 max = Vector2.Zero;
|
||||
|
||||
public Box2( Vector2 min, Vector2 max )
|
||||
{
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public Box2()
|
||||
{}
|
||||
|
||||
public bool ContainsPoint( Vector2 point )
|
||||
{
|
||||
return ContainsPoint( min, max, point );
|
||||
}
|
||||
|
||||
public Box2 Clone()
|
||||
{
|
||||
return new Box2( min, max );
|
||||
}
|
||||
|
||||
public void UnionWith( Box2 other )
|
||||
{
|
||||
min = min.Min( other.min );
|
||||
max = max.Max( other.max );
|
||||
}
|
||||
|
||||
public void Grow( Vector2 abs )
|
||||
{
|
||||
min -= abs;
|
||||
max += abs;
|
||||
}
|
||||
|
||||
public void GrowByPoint( Vector2 p )
|
||||
{
|
||||
min = min.Min( p );
|
||||
max = max.Max( p );
|
||||
}
|
||||
|
||||
public Vector2 size => max - min;
|
||||
|
||||
public void GrowRelativeToSize( float amount )
|
||||
{
|
||||
Grow( size * amount );
|
||||
}
|
||||
|
||||
public static bool ContainsPoint( Vector2 min, Vector2 max, Vector2 point )
|
||||
{
|
||||
if ( ! Range.Contains( min.X, max.X, point.X ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! Range.Contains( min.Y, max.Y, point.Y ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void EnsureCorrectness()
|
||||
{
|
||||
if ( max.X < min.X )
|
||||
{
|
||||
var b = max.X; max.X = min.X; min.X = b;
|
||||
}
|
||||
|
||||
if ( max.Y < min.Y )
|
||||
{
|
||||
var b = max.Y; max.Y = min.Y; min.Y = b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,16 @@ namespace Rokojori
|
|||
return b;
|
||||
}
|
||||
|
||||
|
||||
public Box2 AsXZBox2()
|
||||
{
|
||||
var b = new Box2();
|
||||
b.min = Math2D.XZ( min );
|
||||
b.max = Math2D.XZ( max );
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public Vector3 Constrain( Vector3 point )
|
||||
{
|
||||
point = min.Max( point );
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Capsule2
|
||||
{
|
||||
public Vector2 start = Vector2.Zero;
|
||||
public Vector2 end = Vector2.Zero;
|
||||
public float radius = 1;
|
||||
|
||||
public Capsule2( Vector2 start, Vector2 end, float radius )
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public Capsule2 Copy()
|
||||
{
|
||||
return new Capsule2( start, end, radius );
|
||||
}
|
||||
|
||||
public Vector2 center
|
||||
{
|
||||
get { return start.Lerp( end, 0.5f ); }
|
||||
}
|
||||
|
||||
public Line2 centerLine
|
||||
{
|
||||
get { return new Line2( start, end ); }
|
||||
}
|
||||
|
||||
public float DistanceToPoint( Vector2 p )
|
||||
{
|
||||
var lineDistance = centerLine.DistanceToPoint( p );
|
||||
return Mathf.Max( 0, lineDistance - radius );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Circle
|
||||
{
|
||||
public Vector2 center = Vector2.Zero;
|
||||
public float radius = 1;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Convex2Group
|
||||
{
|
||||
public List<Convex2> items;
|
||||
public Box2 boundingBox;
|
||||
|
||||
public static Convex2Group From( List<Convex2> items )
|
||||
{
|
||||
var group = new Convex2Group();
|
||||
|
||||
group.items = items;
|
||||
|
||||
group.boundingBox = items[ 0 ].boundingBox.Clone();
|
||||
|
||||
items.ForEach( it => group.boundingBox.UnionWith( it.boundingBox ) );
|
||||
|
||||
// RJLog.Log( group.boundingBox );
|
||||
|
||||
return group;
|
||||
|
||||
}
|
||||
|
||||
public static Convex2Group FromPath( Path2 path )
|
||||
{
|
||||
return From( Convex2.PathToConvexList( path ) );
|
||||
}
|
||||
|
||||
public bool ContainsPoint( Vector2 point )
|
||||
{
|
||||
if ( ! boundingBox.ContainsPoint( point ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < items.Count; i++ )
|
||||
{
|
||||
if ( items[ i ].ContainsPoint( point ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class Convex2
|
||||
{
|
||||
public List<Vector2> points;
|
||||
public List<Vector2> normals;
|
||||
public List<Vector2> directions;
|
||||
|
||||
public Box2 boundingBox;
|
||||
public bool clockwise;
|
||||
|
||||
public bool ContainsPoint( Vector2 point, bool checkBounds = true )
|
||||
{
|
||||
if ( checkBounds && ! boundingBox.ContainsPoint( point ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var positive = 0;
|
||||
var negative = 0;
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
var p = points[ i ];
|
||||
var d = directions[ i ].Cross( point - p );
|
||||
|
||||
if ( d > 0 )
|
||||
{
|
||||
positive++;
|
||||
}
|
||||
|
||||
if ( d < 0 )
|
||||
{
|
||||
negative++;
|
||||
}
|
||||
|
||||
if ( positive > 0 && negative > 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<Convex2> PathToConvexList( Path2 path )
|
||||
{
|
||||
var convexPolys = Geometry2D.DecomposePolygonInConvex( path.points.ToArray() );
|
||||
|
||||
var list = new List<Convex2>();
|
||||
|
||||
for ( int i = 0; i < convexPolys.Count; i++ )
|
||||
{
|
||||
var clockwise = Geometry2D.IsPolygonClockwise( convexPolys[ i ] );
|
||||
var cnv = FromConvexHull( convexPolys[ i ], clockwise );
|
||||
|
||||
list.Add( cnv );
|
||||
}
|
||||
|
||||
// RJLog.Log( "PathToConvexList:", list.Count );
|
||||
return list;
|
||||
}
|
||||
|
||||
public static Convex2 FromConvexHull( Vector2[] points, bool isClockwise = true )
|
||||
{
|
||||
return FromConvexHull( new List<Vector2>( points ), isClockwise );
|
||||
}
|
||||
|
||||
public static Convex2 FromConvexHull( List<Vector2> points, bool isClockwise = true )
|
||||
{
|
||||
var cnv = new Convex2();
|
||||
cnv.points = points;
|
||||
cnv.normals = new List<Vector2>();
|
||||
cnv.directions = new List<Vector2>();
|
||||
cnv.clockwise = isClockwise;
|
||||
|
||||
cnv.boundingBox = new Box2( points[ 0 ], points[ 0 ] );
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
var next = ( i + 1 ) % points.Count;
|
||||
|
||||
cnv.boundingBox.GrowByPoint( points[ i ] );
|
||||
|
||||
var direction = points[ next ] - points[ i ];
|
||||
var normal = Math2D.Rotate90Degrees( direction.Normalized(), ! isClockwise );
|
||||
|
||||
cnv.normals.Add( normal );
|
||||
cnv.directions.Add( direction );
|
||||
}
|
||||
|
||||
return cnv;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ namespace Rokojori
|
|||
{
|
||||
public abstract class Curve3
|
||||
{
|
||||
float _gradientSamplingRange = Mathf.Pow( 10f, -13f );
|
||||
float _gradientSamplingRange = Mathf.Pow( 10f, -8f );
|
||||
public abstract Vector3 SampleAt( float t );
|
||||
|
||||
public virtual void SampleMultiple( int numSamples, List<Vector3> output )
|
||||
|
@ -28,8 +28,12 @@ namespace Rokojori
|
|||
|
||||
public virtual Vector3 GradientAt( float t )
|
||||
{
|
||||
return GradientAt( t, _gradientSamplingRange );
|
||||
}
|
||||
|
||||
return SampleAt( t + _gradientSamplingRange ) - SampleAt( t - _gradientSamplingRange );
|
||||
public virtual Vector3 GradientAt( float t, float samplingRange )
|
||||
{
|
||||
return SampleAt( t + samplingRange ) - SampleAt( t - samplingRange );
|
||||
}
|
||||
|
||||
public virtual float ComputeLength( int numSamples )
|
||||
|
@ -71,6 +75,88 @@ namespace Rokojori
|
|||
return Mathf.Max( minSamples, numSamples );
|
||||
}
|
||||
|
||||
public Vector3 GetClosestPositionTo( Vector3 position, int numSegments = 20, int depth = 0 )
|
||||
{
|
||||
var parameter = GetClosestParameterTo( position, numSegments, depth );
|
||||
|
||||
return SampleAt( parameter );
|
||||
}
|
||||
|
||||
public float GetClosestParameterTo( Vector3 point, int numSegments = 20, int depth = 3 )
|
||||
{
|
||||
return GetClosestParameterTo( 0, 1, point, numSegments, depth, 0 );
|
||||
}
|
||||
|
||||
public float GetDistanceTo( Vector3 point, int numSegments = 20, int depth = 3 )
|
||||
{
|
||||
var p = GetClosestPositionTo( point, numSegments, depth );
|
||||
return ( p - point ).Length();
|
||||
}
|
||||
|
||||
protected float GetClosestParameterTo( float tStart, float tEnd, Vector3 position, int numSegments, int maxDepth, int currentDepth = 0 )
|
||||
{
|
||||
var tNormalizer = ( tEnd - tStart ) / (float) ( numSegments - 1 );
|
||||
|
||||
var closestIndex = -1;
|
||||
var closestDistance = float.MaxValue;
|
||||
var minT = 0f;
|
||||
var maxT = 1f;
|
||||
var startPoint = SampleAt( tStart );
|
||||
|
||||
var line = new Line3();
|
||||
var lastT = tStart;
|
||||
|
||||
for ( int i = 1; i < numSegments; i++ )
|
||||
{
|
||||
var t = tNormalizer * i + tStart;
|
||||
var nextCurvePoint = SampleAt( t );
|
||||
|
||||
line.Set( startPoint, nextCurvePoint );
|
||||
|
||||
var closestPoint = line.ClosestPointToPoint( position );
|
||||
|
||||
var distance = ( position - closestPoint ).LengthSquared();
|
||||
|
||||
if ( distance < closestDistance )
|
||||
{
|
||||
closestDistance = distance;
|
||||
closestIndex = i - 1;
|
||||
minT = lastT;
|
||||
maxT = t;
|
||||
}
|
||||
|
||||
startPoint = nextCurvePoint;
|
||||
lastT = t;
|
||||
}
|
||||
|
||||
if ( maxDepth != currentDepth )
|
||||
{
|
||||
return GetClosestParameterTo( minT, maxT, position, numSegments, maxDepth, currentDepth + 1 );
|
||||
}
|
||||
|
||||
var tNormalizer2 = ( maxT - minT ) / (float)(numSegments - 1 );
|
||||
|
||||
closestDistance = float.MaxValue;
|
||||
var closestParameter = 0.5f;
|
||||
|
||||
for ( int i = 0; i < numSegments; i++ )
|
||||
{
|
||||
var detailedT = i * tNormalizer2 + minT;
|
||||
var sampledPoint = SampleAt( detailedT );
|
||||
|
||||
var distance = ( sampledPoint - position ).LengthSquared();
|
||||
|
||||
if ( distance < closestDistance )
|
||||
{
|
||||
closestParameter = detailedT;
|
||||
closestDistance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
return closestParameter;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ namespace Rokojori
|
|||
|
||||
/*
|
||||
|
||||
P = Point,
|
||||
P = Point
|
||||
S = Sphere
|
||||
L = Line,
|
||||
L = Line
|
||||
C = Capsule
|
||||
|
||||
|
||||
|
|
|
@ -30,11 +30,11 @@ namespace Rokojori
|
|||
|
||||
public class LerpCurve3:Curve3
|
||||
{
|
||||
List<Vector3> list;
|
||||
List<Vector3> points;
|
||||
|
||||
public LerpCurve3( List<Vector3> list )
|
||||
{
|
||||
this.list = list;
|
||||
this.points = list;
|
||||
|
||||
if ( list.Count == 0 )
|
||||
{
|
||||
|
@ -45,12 +45,12 @@ namespace Rokojori
|
|||
public override float ComputeLength( int numSamples )
|
||||
{
|
||||
var length = 0f;
|
||||
var end = list.Count - 1;
|
||||
var end = points.Count - 1;
|
||||
|
||||
for ( int i = 0; i < end; i++ )
|
||||
{
|
||||
var p0 = list[ i ];
|
||||
var p1 = list[ i + 1 ];
|
||||
var p0 = points[ i ];
|
||||
var p1 = points[ i + 1 ];
|
||||
|
||||
length += p0.DistanceTo( p1 );
|
||||
}
|
||||
|
@ -58,19 +58,104 @@ namespace Rokojori
|
|||
return length;
|
||||
}
|
||||
|
||||
public int numSegments => points.Count -1;
|
||||
public float GetSegmentDistance( int i )
|
||||
{
|
||||
return ( points[ i + 1 ] - points[ i ] ).Length();
|
||||
}
|
||||
|
||||
public float GetMinimumSegmentDistance()
|
||||
{
|
||||
var min = GetSegmentDistance( 0 );
|
||||
|
||||
for ( int i = 1; i < numSegments; i++ )
|
||||
{
|
||||
min = Mathf.Min( min, GetSegmentDistance( i ) );
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
public LerpCurve3 CreateMinimumSpaced( float minSpace )
|
||||
{
|
||||
var lastPoint = points.Count - 1;
|
||||
|
||||
var spacedPoints = new List<Vector3>();
|
||||
|
||||
var line = new Line3();
|
||||
|
||||
for ( int i = 0; i < lastPoint; i++ )
|
||||
{
|
||||
line.start = points[ i ];
|
||||
line.end = points[ i + 1 ];
|
||||
|
||||
var direction = line.direction;
|
||||
var length = direction.Length();
|
||||
|
||||
var numPoints = Mathf.CeilToInt( length / minSpace );
|
||||
|
||||
for ( int j = 0; j < numPoints - 1; j++ )
|
||||
{
|
||||
var t = j / (float)( numPoints - 1 );
|
||||
spacedPoints.Add( line.SampleAt( t ) );
|
||||
}
|
||||
}
|
||||
|
||||
spacedPoints.Add( points[ points.Count - 1 ] );
|
||||
|
||||
return new LerpCurve3( spacedPoints );
|
||||
|
||||
}
|
||||
|
||||
public static LerpCurve3 SampledFrom( Curve3 curve, int numSamples )
|
||||
{
|
||||
var points = new List<Vector3>();
|
||||
|
||||
for ( int i = 0; i < numSamples; i++ )
|
||||
{
|
||||
var t = i / ( (float) numSamples - 1 );
|
||||
|
||||
var p = curve.SampleAt( t );
|
||||
|
||||
points.Add( p );
|
||||
}
|
||||
|
||||
return new LerpCurve3( points );
|
||||
}
|
||||
|
||||
public static LerpCurve3 SampledWithResolution( Curve3 curve, float resolution, int lengthSampleResolution = 20 )
|
||||
{
|
||||
var length = curve.ComputeLength( lengthSampleResolution );
|
||||
|
||||
var numSamples = Mathf.CeilToInt( length * resolution );
|
||||
|
||||
return SampledFrom( curve, numSamples );
|
||||
}
|
||||
|
||||
public static LerpCurve3 SampledEqually( Curve3 curve, float minDistance, float smallestSegmentDivision = 2, int lengthSampleResolution = 20 )
|
||||
{
|
||||
var lerpCurve = SampledWithResolution( curve, minDistance, lengthSampleResolution );
|
||||
|
||||
var smallestSegment = lerpCurve.GetMinimumSegmentDistance() / smallestSegmentDivision;
|
||||
|
||||
var minSpace = Mathf.Min( smallestSegment, minDistance );
|
||||
|
||||
return lerpCurve.CreateMinimumSpaced( minSpace );
|
||||
}
|
||||
|
||||
public float UndistortParameter( float parameter )
|
||||
{
|
||||
var completeLength = ComputeLength( 0 );
|
||||
|
||||
var end = list.Count - 1;
|
||||
var normalizer = 1f / ( list.Count - 1 );
|
||||
var end = points.Count - 1;
|
||||
var normalizer = 1f / ( points.Count - 1 );
|
||||
|
||||
var length = 0f;
|
||||
|
||||
for ( int i = 0; i < end; i++ )
|
||||
{
|
||||
var p0 = list[ i ];
|
||||
var p1 = list[ i + 1 ];
|
||||
var p0 = points[ i ];
|
||||
var p1 = points[ i + 1 ];
|
||||
var t0 = i * normalizer;
|
||||
var t1 = ( i + 1 ) * normalizer;
|
||||
var distance = p0.DistanceTo( p1 );
|
||||
|
@ -93,7 +178,7 @@ namespace Rokojori
|
|||
{
|
||||
var output = new List<SubdivisionData>();
|
||||
|
||||
var num = list.Count - 1;
|
||||
var num = points.Count - 1;
|
||||
|
||||
if ( close )
|
||||
{
|
||||
|
@ -102,8 +187,8 @@ namespace Rokojori
|
|||
|
||||
for ( var i = 0; i < num; i++ )
|
||||
{
|
||||
var start = list[ i ];
|
||||
var end = list[ i == list.Count ? 0 : i + 1 ];
|
||||
var start = points[ i ];
|
||||
var end = points[ i == points.Count ? 0 : i + 1 ];
|
||||
|
||||
var dir = ( end - start );
|
||||
var length = dir.Length();
|
||||
|
@ -123,8 +208,8 @@ namespace Rokojori
|
|||
|
||||
if ( ! close )
|
||||
{
|
||||
var start = list[ list.Count - 2];
|
||||
var end = list[ list.Count - 1];
|
||||
var start = points[ points.Count - 2];
|
||||
var end = points[ points.Count - 1];
|
||||
|
||||
var dir = ( end - start );
|
||||
|
||||
|
@ -151,33 +236,33 @@ namespace Rokojori
|
|||
{
|
||||
if ( t < 0 )
|
||||
{
|
||||
return list[ 0 ];
|
||||
return points[ 0 ];
|
||||
}
|
||||
|
||||
if ( t >= 1 )
|
||||
{
|
||||
return list[ list.Count - 1 ];
|
||||
return points[ points.Count - 1 ];
|
||||
}
|
||||
|
||||
if ( list.Count == 1 )
|
||||
if ( points.Count == 1 )
|
||||
{
|
||||
return list[ 0 ];
|
||||
return points[ 0 ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
var listIndex = t * ( list.Count - 1 );
|
||||
var listIndex = t * ( points.Count - 1 );
|
||||
var flooredIndex = (int) Mathf.Floor( listIndex );
|
||||
|
||||
var lerpAmount = listIndex - flooredIndex;
|
||||
|
||||
if ( flooredIndex < 0 || ( flooredIndex >= list.Count - 1 ) )
|
||||
if ( flooredIndex < 0 || ( flooredIndex >= points.Count - 1 ) )
|
||||
{
|
||||
RJLog.Log( "Out of range index:",flooredIndex, " t:", t, " listIndex", listIndex, "Count:", list.Count );
|
||||
RJLog.Log( "Out of range index:",flooredIndex, " t:", t, " listIndex", listIndex, "Count:", points.Count );
|
||||
}
|
||||
|
||||
var lower = list[ flooredIndex ];
|
||||
var upper = list[ flooredIndex + 1 ];
|
||||
var lower = points[ flooredIndex ];
|
||||
var upper = points[ flooredIndex + 1 ];
|
||||
|
||||
return Math3D.LerpUnclamped( lower, upper, lerpAmount );
|
||||
|
||||
|
@ -218,14 +303,14 @@ namespace Rokojori
|
|||
line = new Line3( Vector3.Zero, Vector3.Zero );
|
||||
}
|
||||
|
||||
var end = list.Count - 1;
|
||||
var end = points.Count - 1;
|
||||
|
||||
var parameterNormalizer = 1f / ( list.Count - 1f );
|
||||
var parameterNormalizer = 1f / ( points.Count - 1f );
|
||||
|
||||
for ( int i = 0; i < end; i++ )
|
||||
{
|
||||
line.start = list[ i ];
|
||||
line.end = list[ i + 1 ];
|
||||
line.start = points[ i ];
|
||||
line.end = points[ i + 1 ];
|
||||
|
||||
var currentParameter = line.ClostestParameterToPoint( point );
|
||||
var currentClosestPoint = line.GetPointAtParameter( currentParameter );
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Line2
|
||||
{
|
||||
public Vector2 start = Vector2.Zero;
|
||||
public Vector2 end = Vector2.Zero;
|
||||
|
||||
public Line2( Vector2 start, Vector2 end )
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public Line2(){}
|
||||
|
||||
public float A{ get { return end.Y - start.Y; } }
|
||||
public float B{ get { return start.X - end.X; } }
|
||||
public float C{ get { return A * start.X + B * start.Y; } }
|
||||
public Vector2 direction { get { return end - start; } }
|
||||
public Vector2 reverseDirection { get { return start - end; } }
|
||||
public float angle
|
||||
{
|
||||
get {
|
||||
|
||||
var lineDirection = direction;
|
||||
|
||||
return Mathf.Atan2( lineDirection.Y, lineDirection.X );
|
||||
}
|
||||
}
|
||||
|
||||
public float reverseAngle
|
||||
{
|
||||
get {
|
||||
|
||||
var lineDirection = reverseDirection;
|
||||
|
||||
return Mathf.Atan2( lineDirection.Y, lineDirection.X );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Vector2? InfiniteIntersectionOf( Line2 line2 )
|
||||
{
|
||||
var A1 = A;
|
||||
var B1 = B;
|
||||
var A2 = line2.A;
|
||||
var B2 = line2.B;
|
||||
|
||||
var determinant = A1 * B2 - A2 * B1;
|
||||
|
||||
if ( Mathf.Abs( determinant ) < Mathf.Epsilon )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var inverseDeterminant = 1f / determinant;
|
||||
|
||||
var C1 = A1 * start.X + B1 * start.Y;
|
||||
var C2 = A2 * line2.start.X + B2 * line2.start.Y;
|
||||
|
||||
var x = ( B2 * C1 - B1 * C2 ) * inverseDeterminant;
|
||||
var y = ( A1 * C2 - A2 * C1 ) * inverseDeterminant;
|
||||
|
||||
return new Vector2( x, y );
|
||||
}
|
||||
|
||||
public Vector2? IntersectionOf( Line2 other )
|
||||
{
|
||||
var possibleIntersection = InfiniteIntersectionOf( other );
|
||||
|
||||
if ( possibleIntersection == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var point = (Vector2) possibleIntersection;
|
||||
|
||||
if ( ! IsValueInRange( point.X, start.X, end.X ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! IsValueInRange( point.Y, start.Y, end.Y ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! IsValueInRange( point.X, other.start.X, other.end.X ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! IsValueInRange( point.Y, other.start.Y, other.end.Y ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
public bool IntersectsWith( Line2 other )
|
||||
{
|
||||
return IntersectionOf( other ) != null;
|
||||
}
|
||||
|
||||
bool IsValueInRange( float value, float start, float end )
|
||||
{
|
||||
var min = Mathf.Min( start, end );
|
||||
var max = Mathf.Max( start, end );
|
||||
|
||||
return min <= value && value <= max;
|
||||
}
|
||||
|
||||
public Vector2 GetPointAtParameter( float t )
|
||||
{
|
||||
return start + direction * t;
|
||||
}
|
||||
|
||||
public Vector2 ClosestPointToPoint( Vector2 point )
|
||||
{
|
||||
var parameter = MathX.Clamp01( ClostestParameterToPoint( point ) );
|
||||
return GetPointAtParameter( parameter );
|
||||
}
|
||||
|
||||
public float ClostestParameterToPoint( Vector2 point )
|
||||
{
|
||||
var startP = point - start;
|
||||
var startEnd = end - start;
|
||||
var startEnd2 = Math2D.Dot( startEnd, startEnd );
|
||||
var startEnd_startP = Math2D.Dot( startEnd, startP );
|
||||
|
||||
if ( startEnd2 == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var t = startEnd_startP / startEnd2;
|
||||
|
||||
return t;
|
||||
|
||||
}
|
||||
|
||||
public float DistanceToPoint( Vector2 point )
|
||||
{
|
||||
return ( point - ClosestPointToPoint( point ) ).Length();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -15,6 +15,19 @@ namespace Rokojori
|
|||
this.end = end;
|
||||
}
|
||||
|
||||
public Line3(){}
|
||||
|
||||
public static Line3 Create( Vector3 start, Vector3 end )
|
||||
{
|
||||
return new Line3( start, end );
|
||||
}
|
||||
|
||||
public void Set( Vector3 start, Vector3 end )
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public override Vector3 SampleAt( float t )
|
||||
{
|
||||
return start.Lerp( end, t );
|
||||
|
@ -80,6 +93,14 @@ namespace Rokojori
|
|||
return GetPointAtParameter( parameter );
|
||||
}
|
||||
|
||||
public static Vector3 ClosestPointOf( Vector3 p, Vector3 lineStart, Vector3 lineEnd )
|
||||
{
|
||||
var line = new Line3();
|
||||
line.Set( lineStart, lineEnd );
|
||||
|
||||
return line.ClosestPointToPoint( p );
|
||||
}
|
||||
|
||||
public float ClostestParameterToPoint( Vector3 point )
|
||||
{
|
||||
var startP = point - start;
|
||||
|
@ -119,6 +140,51 @@ namespace Rokojori
|
|||
return new Vector3[]{ x, y };
|
||||
}
|
||||
|
||||
public Vector3 ClosestPointTo( Line3 other )
|
||||
{
|
||||
var parameters = ClosestParametersToLine( other );
|
||||
return SampleAt( parameters.X );
|
||||
}
|
||||
|
||||
public Vector3 ClosestPointTo( params Vector3[] points )
|
||||
{
|
||||
var d = float.MaxValue;
|
||||
var id = -1;
|
||||
|
||||
for ( int i = 0; i < points.Length; i++ )
|
||||
{
|
||||
var pd = DistanceToPoint( points[ i ] );
|
||||
|
||||
if ( pd < d )
|
||||
{
|
||||
id = i;
|
||||
d = pd;
|
||||
}
|
||||
}
|
||||
|
||||
return points[ id ];
|
||||
}
|
||||
|
||||
public Vector3 ClosestPointTo( List<Vector3> points )
|
||||
{
|
||||
var d = float.MaxValue;
|
||||
var id = -1;
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
var pd = DistanceToPoint( points[ i ] );
|
||||
|
||||
if ( pd < d )
|
||||
{
|
||||
id = i;
|
||||
d = pd;
|
||||
}
|
||||
}
|
||||
|
||||
return points[ id ];
|
||||
}
|
||||
|
||||
|
||||
public Vector2 ClosestParametersToLine( Line3 s )
|
||||
{
|
||||
float epsilon = 0.00000001f;
|
||||
|
|
|
@ -0,0 +1,380 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum PointInPathResult
|
||||
{
|
||||
INSIDE,
|
||||
OUTSIDE,
|
||||
ERROR
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class Path2
|
||||
{
|
||||
float POINT_TO_CLOSE_DISTANCE = 0.0001f;
|
||||
float ANGLE_TO_SIMILAR_TRESHOLD = 0.00001f / 180f;
|
||||
int NUM_POINT_IN_PATH_TEST_RETRIES = 5;
|
||||
|
||||
List<Vector2> _points = new List<Vector2>();
|
||||
|
||||
public List<Vector2> points => _points;
|
||||
|
||||
|
||||
public Path2( List<Vector2> points )
|
||||
{
|
||||
this._points = points;
|
||||
}
|
||||
|
||||
public int numPoints => _points.Count;
|
||||
public bool empty => _points.Count == 0;
|
||||
|
||||
public bool cacheBounds = true;
|
||||
|
||||
Vector2? min;
|
||||
Vector2? max;
|
||||
|
||||
public Vector2 leftTop
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( cacheBounds && min != null )
|
||||
{
|
||||
return (Vector2) min;
|
||||
}
|
||||
|
||||
var _min = _points[ 0 ];
|
||||
|
||||
for ( int i = 1; i < _points.Count; i++ )
|
||||
{
|
||||
var point = _points[ i ];
|
||||
_min.X = Mathf.Min( point.X, _min.X );
|
||||
_min.Y = Mathf.Min( point.Y, _min.Y );
|
||||
}
|
||||
|
||||
min = _min;
|
||||
|
||||
return (Vector2) min;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 rightBottom
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
if ( cacheBounds && max != null )
|
||||
{
|
||||
return (Vector2) max;
|
||||
}
|
||||
|
||||
var _max = _points[ 0 ];
|
||||
|
||||
for ( int i = 1; i < _points.Count; i++ )
|
||||
{
|
||||
var point = _points[ i ];
|
||||
_max.X = Mathf.Max( point.X, _max.X );
|
||||
_max.Y = Mathf.Max( point.Y, _max.Y );
|
||||
}
|
||||
|
||||
max = _max;
|
||||
|
||||
return (Vector2) max;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToNavigationPolygon( NavigationPolygon polygon )
|
||||
{
|
||||
var convexPolygons = Geometry2D.DecomposePolygonInConvex( points.ToArray() );
|
||||
|
||||
for ( int i = 0; i < convexPolygons.Count; i++ )
|
||||
{
|
||||
var vertices = convexPolygons[ i ];
|
||||
polygon.SetVertices( vertices );
|
||||
polygon.AddPolygon( CreateIndices( vertices.Length ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static int[] CreateIndices( int amount )
|
||||
{
|
||||
var indices = new int[ amount ];
|
||||
|
||||
for ( int i = 0; i < amount; i++ )
|
||||
{
|
||||
indices[ i ] = i;
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
public static Path2 AsXZFrom( Curve3D curve3D, bool closed, int resolution = 20 )
|
||||
{
|
||||
var points = new List<Vector2>();
|
||||
|
||||
var numPoints = resolution;
|
||||
|
||||
var normalizer = 1f / resolution;
|
||||
|
||||
for ( int i = 0; i < numPoints; i++ )
|
||||
{
|
||||
points.Add( Math2D.XZ( curve3D.Samplef( i * normalizer ) ) );
|
||||
}
|
||||
|
||||
if ( closed )
|
||||
{
|
||||
points.Add( points[ 0 ] );
|
||||
}
|
||||
|
||||
return new Path2( points );
|
||||
}
|
||||
|
||||
public static Path2 AsXZFrom( Curve3 curve3, bool closed, int resolution = 20 )
|
||||
{
|
||||
var points = new List<Vector2>();
|
||||
|
||||
var numPoints = resolution;
|
||||
|
||||
var normalizer = 1f / resolution;
|
||||
|
||||
for ( int i = 0; i < numPoints; i++ )
|
||||
{
|
||||
points.Add( Math2D.XZ( curve3.SampleAt( i * normalizer ) ) );
|
||||
}
|
||||
|
||||
if ( closed )
|
||||
{
|
||||
points.Add( points[ 0 ] );
|
||||
}
|
||||
|
||||
return new Path2( points );
|
||||
}
|
||||
|
||||
public bool PointInPath( Vector2 p, bool fast = true, bool checkBoundingBox = true )
|
||||
{
|
||||
if ( fast )
|
||||
{
|
||||
return PointInPathFast( p, checkBoundingBox );
|
||||
}
|
||||
else
|
||||
{
|
||||
return PointInPathReliable( p, checkBoundingBox );
|
||||
}
|
||||
}
|
||||
|
||||
public bool PointInPathFast( Vector2 point, bool checkBoundingBox = true )
|
||||
{
|
||||
var min = this.leftTop;
|
||||
var max = this.rightBottom;
|
||||
|
||||
if ( checkBoundingBox )
|
||||
{
|
||||
if ( ! Box2.ContainsPoint( min, max, point ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return CheckPointInPathFast( point, max + new Vector2( 122.133544f, 129.45423f ) );
|
||||
}
|
||||
|
||||
public bool PointInPathReliable( Vector2 point, bool checkBoundingBox = true )
|
||||
{
|
||||
var min = this.leftTop;
|
||||
var max = this.rightBottom;
|
||||
|
||||
if ( checkBoundingBox )
|
||||
{
|
||||
if ( ! Box2.ContainsPoint( min, max, point ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var endPoint = max + new Vector2( 0.1234235f, 0.4211322f );
|
||||
var result = CheckPointInPath( point, endPoint );
|
||||
|
||||
if ( PointInPathResult.ERROR != result )
|
||||
{
|
||||
return PointInPathResult.INSIDE == result;
|
||||
}
|
||||
|
||||
var rightTop = new Vector2( max.X, min.Y );
|
||||
endPoint = rightTop + new Vector2( 0.03234235f, -0.90211322f );
|
||||
result = CheckPointInPath( point, endPoint );
|
||||
|
||||
if ( PointInPathResult.ERROR != result )
|
||||
{
|
||||
return PointInPathResult.INSIDE == result;
|
||||
}
|
||||
|
||||
var centerTop = new Vector2( ( min.X + max.X ) * 0.5f , min.Y );
|
||||
endPoint = centerTop + new Vector2( 0.013234235f, -0.90211322f );
|
||||
result = CheckPointInPath( point, endPoint );
|
||||
|
||||
if ( PointInPathResult.ERROR != result )
|
||||
{
|
||||
return PointInPathResult.INSIDE == result;
|
||||
}
|
||||
|
||||
var rightMiddle = new Vector2( max.X , ( min.Y + max.Y ) * 0.5f);
|
||||
endPoint = rightMiddle + new Vector2( 0.013234235f, 0.00211322f );
|
||||
result = CheckPointInPath( point, endPoint );
|
||||
|
||||
if ( PointInPathResult.ERROR != result )
|
||||
{
|
||||
return PointInPathResult.INSIDE == result;
|
||||
}
|
||||
|
||||
endPoint = leftTop + new Vector2( -0.01053535f, -0.41005465f );
|
||||
result = CheckPointInPath( point, endPoint );
|
||||
|
||||
if ( PointInPathResult.ERROR != result )
|
||||
{
|
||||
return PointInPathResult.INSIDE == result;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < NUM_POINT_IN_PATH_TEST_RETRIES; i++ )
|
||||
{
|
||||
var randomX = GodotRandom.Get().Next();
|
||||
var randomY = GodotRandom.Get().Next();
|
||||
|
||||
var randomPoint = max + new Vector2( randomX, randomY );
|
||||
result = CheckPointInPath( point, endPoint );
|
||||
|
||||
if ( PointInPathResult.ERROR != result )
|
||||
{
|
||||
return PointInPathResult.INSIDE == result;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CheckPointInPathFast( Vector2 point, Vector2 endPoint )
|
||||
{
|
||||
var pointLine = new Line2( point, endPoint );
|
||||
|
||||
var iterationLine = new Line2();
|
||||
|
||||
var intersections = 0;
|
||||
|
||||
for ( int i = 0; i < _points.Count; i++ )
|
||||
{
|
||||
var start = _points[ i ];
|
||||
|
||||
var nextIndex = ( i == _points.Count - 1 ) ? 0 : ( i + 1 );
|
||||
var end = _points[ nextIndex ];
|
||||
|
||||
|
||||
iterationLine.start = start;
|
||||
iterationLine.end = end;
|
||||
|
||||
var intersects = pointLine.IntersectsWith( iterationLine );
|
||||
|
||||
if ( intersects )
|
||||
{
|
||||
intersections ++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return intersections % 2 != 0;
|
||||
}
|
||||
|
||||
PointInPathResult CheckPointInPath( Vector2 point, Vector2 endPoint )
|
||||
{
|
||||
var pointLine = new Line2( point, endPoint );
|
||||
var pointAngle = pointLine.angle;
|
||||
var pointAngle2 = pointLine.reverseAngle;
|
||||
|
||||
var iterationLine = new Line2();
|
||||
|
||||
var intersections = 0;
|
||||
|
||||
for ( int i = 0; i < _points.Count; i++ )
|
||||
{
|
||||
var start = _points[ i ];
|
||||
|
||||
if ( pointLine.DistanceToPoint( start ) < POINT_TO_CLOSE_DISTANCE )
|
||||
{
|
||||
return PointInPathResult.ERROR;
|
||||
}
|
||||
|
||||
var nextIndex = ( i == _points.Count - 1 ) ? 0 : ( i + 1 );
|
||||
var end = _points[ nextIndex ];
|
||||
|
||||
|
||||
iterationLine.start = _points[ i ];
|
||||
iterationLine.end = _points[ nextIndex ];
|
||||
|
||||
var iterationAngle = iterationLine.angle;
|
||||
var angleDifference = AbsoluteDeltaAngleFromRadiansToDegrees( pointAngle, iterationAngle );
|
||||
|
||||
if ( angleDifference < ANGLE_TO_SIMILAR_TRESHOLD )
|
||||
{
|
||||
return PointInPathResult.ERROR;
|
||||
}
|
||||
|
||||
angleDifference = AbsoluteDeltaAngleFromRadiansToDegrees( pointAngle2, iterationAngle );
|
||||
|
||||
if ( angleDifference < ANGLE_TO_SIMILAR_TRESHOLD )
|
||||
{
|
||||
return PointInPathResult.ERROR;
|
||||
}
|
||||
|
||||
|
||||
var intersects = pointLine.IntersectsWith( iterationLine );
|
||||
|
||||
if ( intersects )
|
||||
{
|
||||
intersections ++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( intersections % 2 != 0 )
|
||||
{
|
||||
return PointInPathResult.INSIDE;
|
||||
}
|
||||
|
||||
return PointInPathResult.OUTSIDE;
|
||||
|
||||
}
|
||||
|
||||
public static Path2 Circle( Vector2 center, float radius = 1, int resolution = 36 )
|
||||
{
|
||||
var points = new List<Vector2>();
|
||||
|
||||
for ( int i = 0; i < resolution; i++ )
|
||||
{
|
||||
var t = i / ( float ) ( resolution );
|
||||
var phase = t * Mathf.Pi * 2;
|
||||
var x = Mathf.Cos( phase ) * radius;
|
||||
var y = Mathf.Sin( phase ) * radius;
|
||||
|
||||
points.Add( new Vector2( x, y ) + center );
|
||||
}
|
||||
|
||||
return new Path2( points );
|
||||
}
|
||||
|
||||
|
||||
public static float AbsoluteDeltaAngleFromRadiansToDegrees( float rA, float rB )
|
||||
{
|
||||
var dA = Mathf.RadToDeg( rA );
|
||||
var dB = Mathf.RadToDeg( rB );
|
||||
|
||||
return MathX.AbsoluteDeltaAngle( dA, dB );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Plane3
|
||||
{
|
||||
public Vector3 normal = Vector3.Up;
|
||||
public float constant = 0;
|
||||
|
||||
|
||||
public Plane3(){}
|
||||
|
||||
public void Set( Vector3 normal, float constant = 0 )
|
||||
{
|
||||
this.normal = normal;
|
||||
this.constant = constant;
|
||||
}
|
||||
|
||||
public Vector3 ConstrainToPlane( Vector3 p, float distance = 10000 )
|
||||
{
|
||||
var line3 = new Line3();
|
||||
line3.Set( p - normal * distance, p + normal * distance );
|
||||
|
||||
var intersection = IntersectLine( line3 );
|
||||
|
||||
if ( intersection == null )
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
return (Vector3) intersection;
|
||||
}
|
||||
|
||||
public Vector3 ClosestPointTo( Vector3 p )
|
||||
{
|
||||
return ConstrainToPlane( p );
|
||||
}
|
||||
|
||||
public float DistanceTo( Vector3 p, float normalIntersectionDistance = 5000 )
|
||||
{
|
||||
var line = Line3.Create( p - normal * normalIntersectionDistance, p + normal * normalIntersectionDistance );
|
||||
var isc = IntersectLine( line );
|
||||
|
||||
if ( isc == null )
|
||||
{
|
||||
return float.PositiveInfinity;
|
||||
}
|
||||
|
||||
var xp = (Vector3)isc;
|
||||
|
||||
return ( p - xp ).Length();
|
||||
}
|
||||
|
||||
public Ray3 GetIntersectionRay( Plane3 other )
|
||||
{
|
||||
var lineDirection = normal.Cross( other.normal );
|
||||
|
||||
var det = lineDirection.LengthSquared();
|
||||
|
||||
if ( det == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var r = new Ray3();
|
||||
r.offset = ( ( lineDirection.Cross( other.normal ) * constant ) +
|
||||
( normal.Cross( lineDirection ) * other.constant ) ) / det;
|
||||
|
||||
r.direction = lineDirection;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public Vector3? IntersectLine( Line3 line )
|
||||
{
|
||||
var direction = line.direction;
|
||||
|
||||
var denominator = Math3D.Dot( normal, direction );
|
||||
|
||||
if ( denominator == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var t = - ( Math3D.Dot( line.start, normal ) + constant ) / denominator;
|
||||
|
||||
if ( t < 0 || t > 1 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return direction * t + line.start;
|
||||
}
|
||||
|
||||
public static Plane3 GetZeroUp()
|
||||
{
|
||||
var plane = new Plane3();
|
||||
plane.Set( Vector3.Up, 0 );
|
||||
return plane;
|
||||
}
|
||||
|
||||
public void SetFromNormalAndCoplanarPoint( Vector3 normal, Vector3 point )
|
||||
{
|
||||
this.normal = normal;
|
||||
this.constant = - Math3D.Dot( point, this.normal );
|
||||
}
|
||||
|
||||
public void SetFromCoplanarPoints( Vector3 a, Vector3 b, Vector3 c )
|
||||
{
|
||||
var normal = Math3D.ComputeNormal( a, b, c );
|
||||
SetFromNormalAndCoplanarPoint( normal, a );
|
||||
}
|
||||
|
||||
public static Plane3 FromCoplanarPoints( Vector3 a, Vector3 b, Vector3 c )
|
||||
{
|
||||
var p = new Plane3();
|
||||
p.SetFromCoplanarPoints( a, b, c );
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Pose
|
||||
{
|
||||
bool _needsUpdate = true;
|
||||
Quaternion _rotation = Quaternion.Identity;
|
||||
public Quaternion rotation
|
||||
{
|
||||
get => _rotation;
|
||||
set
|
||||
{
|
||||
_rotation = value;
|
||||
_needsUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 _position = Vector3.Zero;
|
||||
public Vector3 position
|
||||
{
|
||||
get => _position;
|
||||
set
|
||||
{
|
||||
_position = value;
|
||||
_needsUpdate = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Basis _basis;
|
||||
|
||||
void Update()
|
||||
{
|
||||
if ( ! _needsUpdate )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_needsUpdate = false;
|
||||
|
||||
_basis = new Basis( _rotation );
|
||||
}
|
||||
|
||||
public Vector3 forward
|
||||
{
|
||||
get
|
||||
{
|
||||
Update();
|
||||
|
||||
return -_basis.Z;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 right
|
||||
{
|
||||
get
|
||||
{
|
||||
Update();
|
||||
|
||||
return _basis.X;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 up
|
||||
{
|
||||
get
|
||||
{
|
||||
Update();
|
||||
|
||||
return _basis.Y;
|
||||
}
|
||||
}
|
||||
|
||||
public Pose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Pose ToGlobal( Node3D n )
|
||||
{
|
||||
var p = new Pose();
|
||||
p.rotation = rotation * n.GetGlobalQuaternion();
|
||||
p.position = n.ToGlobal( position );
|
||||
return p;
|
||||
}
|
||||
|
||||
public Vector3 Apply( Vector3 p )
|
||||
{
|
||||
p = rotation * p;
|
||||
p += position;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Ray3
|
||||
{
|
||||
public Vector3 offset;
|
||||
public Vector3 direction;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
public class SAT2
|
||||
{
|
||||
public static void Project( Vector2 normal, List<Vector2> points, Range outputProjectionRange )
|
||||
{
|
||||
var min = float.MaxValue;
|
||||
var max = - float.MaxValue;
|
||||
|
||||
for ( var i = 0; i < points.Count; i++ )
|
||||
{
|
||||
var dot = Math2D.Dot( normal, points[ i ] );
|
||||
|
||||
min = Mathf.Min( min, dot );
|
||||
max = Mathf.Max( max, dot );
|
||||
}
|
||||
|
||||
outputProjectionRange.min = min;
|
||||
outputProjectionRange.max = max;
|
||||
}
|
||||
|
||||
public static bool IsIntersecting(
|
||||
List<Vector2> normalsA, List<Vector2> pointsA,
|
||||
List<Vector2> normalsB, List<Vector2> pointsB )
|
||||
{
|
||||
var projectionRangeA = new Range( 0, 1 );
|
||||
var projectionRangeB = new Range( 0, 1 );
|
||||
|
||||
for ( var i = 0; i < normalsA.Count; i++ )
|
||||
{
|
||||
var axis = normalsA[ i ];
|
||||
|
||||
Project( axis, pointsA, projectionRangeA );
|
||||
Project( axis, pointsB, projectionRangeB );
|
||||
|
||||
if ( ! projectionRangeA.Overlaps( projectionRangeB ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for ( var i = 0; i < normalsB.Count; i++ )
|
||||
{
|
||||
var axis = normalsB[ i ];
|
||||
Project( axis, pointsA, projectionRangeA );
|
||||
Project( axis, pointsB, projectionRangeB );
|
||||
|
||||
if ( ! projectionRangeA.Overlaps( projectionRangeB ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
public class SAT3
|
||||
{
|
||||
|
||||
public static bool IsIntersecting(
|
||||
List<Vector3> pointsA, List<Vector3> faceNormalsA, List<Vector3> edgeDirectionsA,
|
||||
List<Vector3> pointsB, List<Vector3> faceNormalsB, List<Vector3> edgeDirectionsB
|
||||
)
|
||||
{
|
||||
for ( var i = 0; i < faceNormalsA.Count; i++ )
|
||||
{
|
||||
var axis = faceNormalsA[ i ];
|
||||
|
||||
if ( ProjectionsHaveGap( axis, pointsA, pointsB ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for ( var i = 0; i < faceNormalsB.Count; i++ )
|
||||
{
|
||||
var axis = faceNormalsB[ i ];
|
||||
|
||||
if ( ProjectionsHaveGap( axis, pointsA, pointsB ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for ( var i = 0; i < edgeDirectionsA.Count; i++ )
|
||||
{
|
||||
var edgeA = edgeDirectionsA[ i ];
|
||||
|
||||
for ( var j = 0; j < edgeDirectionsB.Count; j++ )
|
||||
{
|
||||
var edgeB = edgeDirectionsB[ j ];
|
||||
|
||||
var axis = edgeA.Cross( edgeB );
|
||||
|
||||
if ( ProjectionsHaveGap( axis, pointsA, pointsB ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ProjectionsHaveGap( Vector3 axis, List<Vector3> a, List<Vector3> b )
|
||||
{
|
||||
var projectionRangeA = Project( axis, a );
|
||||
var projectionRangeB = Project( axis, b );
|
||||
|
||||
return ! projectionRangeA.Overlaps( projectionRangeB );
|
||||
}
|
||||
|
||||
public static Range Project( Vector3 axis, List<Vector3> points )
|
||||
{
|
||||
var min = float.MaxValue;
|
||||
var max = - float.MaxValue;
|
||||
|
||||
for ( var i = 0; i < points.Count; i++ )
|
||||
{
|
||||
var dot = Math3D.Dot( axis, points[ i ] );
|
||||
|
||||
min = Mathf.Min( min, dot );
|
||||
max = Mathf.Max( max, dot );
|
||||
}
|
||||
|
||||
return new Range( min, max );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,17 @@ namespace Rokojori
|
|||
this.radius = radius;
|
||||
}
|
||||
|
||||
public Sphere(){}
|
||||
|
||||
public Sphere Create( Vector3 center, float radius )
|
||||
{
|
||||
var sphere = new Sphere();
|
||||
sphere.center = center;
|
||||
sphere.radius = radius;
|
||||
|
||||
return sphere;
|
||||
}
|
||||
|
||||
public Sphere Copy()
|
||||
{
|
||||
return new Sphere( center, radius );
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SplineCurveTangent
|
||||
{
|
||||
public Vector3 position;
|
||||
public float weight = 1f;
|
||||
|
||||
public SplineCurveTangent Clone()
|
||||
{
|
||||
var t = new SplineCurveTangent();
|
||||
t.position = position;
|
||||
t.weight = weight;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SplineCurvePoint
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public float weight = 1f;
|
||||
|
||||
public SplineCurveTangent tangentBefore = new SplineCurveTangent();
|
||||
public SplineCurveTangent tangentNext = new SplineCurveTangent();
|
||||
|
||||
public SplineCurvePoint Clone()
|
||||
{
|
||||
var scp = new SplineCurvePoint();
|
||||
scp.position = position;
|
||||
scp.rotation = rotation;
|
||||
scp.weight = weight;
|
||||
scp.tangentBefore = tangentBefore.Clone();
|
||||
scp.tangentNext = tangentNext.Clone();
|
||||
|
||||
return scp;
|
||||
}
|
||||
|
||||
public SplineCurvePoint CloneForXZ( float y )
|
||||
{
|
||||
var cloned = Clone();
|
||||
cloned.position.Y = y;
|
||||
cloned.tangentBefore.position.Y = 0;
|
||||
cloned.tangentNext.position.Y = 0;
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SplineCurve: Curve3
|
||||
{
|
||||
List<SplineCurvePoint> _points = new List<SplineCurvePoint>();
|
||||
|
||||
public List<SplineCurvePoint> points => _points;
|
||||
|
||||
public static SplineCurve From( List<SplineCurvePoint> points )
|
||||
{
|
||||
var splineCurve = new SplineCurve();
|
||||
splineCurve._points = points;
|
||||
return splineCurve;
|
||||
}
|
||||
|
||||
public Vector3 MinPointPosition()
|
||||
{
|
||||
var min = _points[ 0 ].position;
|
||||
|
||||
points.ForEach( p => min = min.Min( p.position ) );
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
public Vector3 MaxPointPosition()
|
||||
{
|
||||
var max = _points[ 0 ].position;
|
||||
|
||||
points.ForEach( p => max = max.Max( p.position ) );
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
public SplineCurve Clone()
|
||||
{
|
||||
var splineCurve = new SplineCurve();
|
||||
splineCurve._points = Lists.Map( points, p => p.Clone() );
|
||||
return splineCurve;
|
||||
}
|
||||
|
||||
public SplineCurve CloneForXZ( float y )
|
||||
{
|
||||
var splineCurve = new SplineCurve();
|
||||
splineCurve._points = Lists.Map( points, p => p.CloneForXZ( y ) );
|
||||
return splineCurve;
|
||||
}
|
||||
|
||||
|
||||
public Vector3 GetByPointIndex( float pointIndex )
|
||||
{
|
||||
if ( pointIndex <= 0 )
|
||||
{
|
||||
return _points[ 0 ].position;
|
||||
}
|
||||
|
||||
if ( pointIndex >= ( _points.Count - 1 ) )
|
||||
{
|
||||
return _points[ _points.Count - 1 ].position;
|
||||
}
|
||||
|
||||
var lower = Mathf.FloorToInt( pointIndex );
|
||||
var higher = Mathf.CeilToInt( pointIndex );
|
||||
|
||||
var lerpAmount = pointIndex - lower;
|
||||
|
||||
return RationalCubicBezier.Compute(
|
||||
lerpAmount,
|
||||
|
||||
_points[ lower ].position,
|
||||
_points[ lower ].tangentNext.position,
|
||||
_points[ higher ].tangentBefore.position,
|
||||
_points[ higher ].position,
|
||||
|
||||
_points[ lower ].weight,
|
||||
_points[ lower ].tangentNext.weight,
|
||||
_points[ higher ].tangentBefore.weight,
|
||||
_points[ higher ].weight
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
public override Vector3 SampleAt( float t )
|
||||
{
|
||||
if ( _points.Count <= 0 )
|
||||
{
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
var index = NormalizedToPointIndex( t );
|
||||
|
||||
return GetByPointIndex( index );
|
||||
}
|
||||
|
||||
public float NormalizedToPointIndex( float normalized )
|
||||
{
|
||||
return normalized * ( _points.Count - 1 );
|
||||
}
|
||||
|
||||
public float PointIndexToNormalized( float pointIndex )
|
||||
{
|
||||
return pointIndex / ( _points.Count - 1 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SplineCurveCreator
|
||||
{
|
||||
bool closed;
|
||||
|
||||
public SplineCurve Create( List<SplinePoint> splinePoints, bool close )
|
||||
{
|
||||
closed = close;
|
||||
var points = new List<SplineCurvePoint>();
|
||||
|
||||
for ( int i = 0; i < splinePoints.Count; i++ )
|
||||
{
|
||||
points.Add( CreatePoint( splinePoints, i ) );
|
||||
}
|
||||
|
||||
if ( closed )
|
||||
{
|
||||
points.Add( CreatePoint( splinePoints, 0 ) );
|
||||
}
|
||||
|
||||
return SplineCurve.From( points );
|
||||
}
|
||||
|
||||
SplineCurvePoint CreatePoint( List<SplinePoint> splinePoints, int index )
|
||||
{
|
||||
var splineCurvePoint = new SplineCurvePoint();
|
||||
var splinePoint = splinePoints[ index ];
|
||||
splineCurvePoint.position = splinePoint.GlobalPosition;
|
||||
splineCurvePoint.weight = 1f;
|
||||
|
||||
splineCurvePoint.tangentBefore.position = GetTangentPosition( splinePoints, index, true );
|
||||
splineCurvePoint.tangentNext.position = GetTangentPosition( splinePoints, index, false );
|
||||
|
||||
splineCurvePoint.tangentBefore.weight = splinePoint.tangentBeforeWeight;
|
||||
splineCurvePoint.tangentNext.weight = splinePoint.tangentNextWeight;
|
||||
|
||||
return splineCurvePoint;
|
||||
}
|
||||
|
||||
public Vector3 GetTangentPosition( List<SplinePoint> splinePoints, int index, bool before )
|
||||
{
|
||||
var splinePoint = splinePoints[ index ];
|
||||
|
||||
if ( splinePoint.tangentMode == SplinePointTangentMode.Custom )
|
||||
{
|
||||
return before ? splinePoint.tangentBefore.GlobalPosition :
|
||||
splinePoint.tangentNext.GlobalPosition;
|
||||
}
|
||||
|
||||
var previousIndex = index - 1;
|
||||
|
||||
if ( previousIndex == -1 )
|
||||
{
|
||||
previousIndex = closed ? splinePoints.Count -1 : 0;
|
||||
}
|
||||
|
||||
var nextIndex = index + 1;
|
||||
|
||||
if ( nextIndex == splinePoints.Count )
|
||||
{
|
||||
nextIndex = closed ? 0 : splinePoints.Count - 1;
|
||||
}
|
||||
|
||||
var previous = splinePoints[ previousIndex ];
|
||||
var next = splinePoints[ nextIndex ];
|
||||
|
||||
var previousPosition = previous.GlobalPosition;
|
||||
var nextPosition = next.GlobalPosition;
|
||||
|
||||
|
||||
|
||||
var point = splinePoint.GlobalPosition;
|
||||
|
||||
var overshootPrevention = splinePoint.overshootPrevention;
|
||||
var tangentScale = splinePoint.tangentScale;
|
||||
var symmetricTangentLength = splinePoint.symmetricTangentLength;
|
||||
|
||||
if ( overshootPrevention > 0 )
|
||||
{
|
||||
var previousDirection = ( previousPosition - point ) ;
|
||||
var nextDirection = ( nextPosition - point );
|
||||
|
||||
var previousLength = previousDirection.Length();
|
||||
var nextLength = nextDirection.Length();
|
||||
|
||||
if ( previousLength > nextLength )
|
||||
{
|
||||
previousPosition = Math3D.Lerp(
|
||||
previousPosition, point + previousDirection.Normalized() * nextLength,
|
||||
overshootPrevention
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
nextPosition = Math3D.Lerp(
|
||||
nextPosition, point + nextDirection.Normalized() * previousLength,
|
||||
overshootPrevention
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var direction = nextPosition - previousPosition;
|
||||
var length = 0f;
|
||||
|
||||
var lengthBefore = ( point - previousPosition ).Length();
|
||||
var lengthNext = ( point - nextPosition ).Length();
|
||||
|
||||
var lengthAverage = ( lengthBefore + lengthNext ) * 0.5f;
|
||||
|
||||
if ( symmetricTangentLength > 0 )
|
||||
{
|
||||
lengthBefore = Mathf.Lerp( lengthBefore, lengthAverage, symmetricTangentLength );
|
||||
lengthNext = Mathf.Lerp( lengthNext, lengthAverage, symmetricTangentLength );
|
||||
}
|
||||
|
||||
if ( before )
|
||||
{
|
||||
length = -lengthBefore;
|
||||
}
|
||||
else
|
||||
{
|
||||
length = lengthNext;
|
||||
}
|
||||
|
||||
return point + direction.Normalized() * length * 0.33333f * tangentScale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -5,22 +5,6 @@ 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
|
||||
{
|
||||
|
@ -33,6 +17,8 @@ namespace Rokojori
|
|||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = c;
|
||||
|
||||
_needsUpdate = true;
|
||||
}
|
||||
|
||||
public float perimeter
|
||||
|
@ -47,14 +33,45 @@ namespace Rokojori
|
|||
}
|
||||
}
|
||||
|
||||
public float semiperimeter
|
||||
public float semiperimeter => perimeter * 0.5f;
|
||||
|
||||
Vector3 _center;
|
||||
Sphere _boundingSphere;
|
||||
Plane3 _plane;
|
||||
|
||||
bool _needsUpdate = false;
|
||||
|
||||
public void NeedsUpdate()
|
||||
{
|
||||
_needsUpdate = true;
|
||||
}
|
||||
|
||||
public Sphere boundingSphere
|
||||
{
|
||||
get
|
||||
{
|
||||
return perimeter * 0.5f;
|
||||
Update();
|
||||
return _boundingSphere;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if ( ! _needsUpdate )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var m = Math3D.Center( a, b, c );
|
||||
var radius = Mathf.Sqrt( MathX.Min( ( m - a ).LengthSquared(), ( m - b ).LengthSquared(), ( m -c ).LengthSquared() ) );
|
||||
_boundingSphere = new Sphere( m, radius );
|
||||
|
||||
_plane = new Plane3();
|
||||
_plane.SetFromCoplanarPoints( a, b, c );
|
||||
|
||||
_needsUpdate = false;
|
||||
}
|
||||
|
||||
public static float ComputeTriangleArea( Vector3 a, Vector3 b, Vector3 c )
|
||||
{
|
||||
var sideA = ( b - a ).Length();
|
||||
|
@ -71,26 +88,266 @@ namespace Rokojori
|
|||
return areaValue;
|
||||
}
|
||||
|
||||
public float area
|
||||
public float area => ComputeTriangleArea( a, b, c );
|
||||
|
||||
public bool Intersects( Line3 line )
|
||||
{
|
||||
get
|
||||
var planePoint = _plane.IntersectLine( line );
|
||||
|
||||
if ( planePoint == null )
|
||||
{
|
||||
return ComputeTriangleArea( a, b, c );
|
||||
return false;
|
||||
}
|
||||
|
||||
return InsideTriangle( (Vector3) planePoint, a, b, c );
|
||||
}
|
||||
|
||||
|
||||
public Line3 GetSide( TriangleSide side )
|
||||
public Vector3? GetIntersection( Line3 line )
|
||||
{
|
||||
switch ( side )
|
||||
Update();
|
||||
|
||||
var planePoint = _plane.IntersectLine( line );
|
||||
|
||||
if ( planePoint == null )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if ( ! InsideTriangle( (Vector3) planePoint, a, b, c ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return planePoint;
|
||||
}
|
||||
|
||||
public bool PointInside( Vector3 p )
|
||||
{
|
||||
return InsideTriangle( p, a, b, c );
|
||||
}
|
||||
|
||||
public Vector3 ClosestPoint( Vector3 p )
|
||||
{
|
||||
Update();
|
||||
|
||||
var planePoint = _plane.ClosestPointTo( p );
|
||||
|
||||
if ( PointInside( planePoint ) )
|
||||
{
|
||||
return planePoint;
|
||||
}
|
||||
|
||||
return ClosestPointToEdges( p );
|
||||
|
||||
}
|
||||
|
||||
public Vector3? GetPointOnPlaneInsideTriangle( Vector3 p )
|
||||
{
|
||||
Update();
|
||||
|
||||
var planePoint = _plane.ClosestPointTo( p );
|
||||
|
||||
if ( PointInside( planePoint ) )
|
||||
{
|
||||
return planePoint;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Vector3[] closestPoints = new Vector3[3];
|
||||
|
||||
public Vector3 ClosestPointToEdges( Vector3 p )
|
||||
{
|
||||
closestPoints[ 0 ] = Line3.ClosestPointOf( p, a, b );
|
||||
closestPoints[ 1 ] = Line3.ClosestPointOf( p, b, c );
|
||||
closestPoints[ 2 ] = Line3.ClosestPointOf( p, c, a );
|
||||
|
||||
return Math3D.GetClosest( p, closestPoints );
|
||||
}
|
||||
|
||||
public Vector3 ClosestPoint( Line3 line )
|
||||
{
|
||||
var intersection = GetIntersection( line );
|
||||
|
||||
if ( intersection != null )
|
||||
{
|
||||
return (Vector3) intersection;
|
||||
}
|
||||
|
||||
var ab = new Line3( a, b ).ClosestPointTo( line );
|
||||
var bc = new Line3( b, c ).ClosestPointTo( line );
|
||||
var ca = new Line3( c, a ).ClosestPointTo( line );
|
||||
|
||||
return line.ClosestPointTo( ab, bc, ca );
|
||||
}
|
||||
|
||||
public Vector3 GetPoint( int i )
|
||||
{
|
||||
if ( i == 0 )
|
||||
{
|
||||
return a;
|
||||
}
|
||||
else if ( i == 1 )
|
||||
{
|
||||
return b;
|
||||
}
|
||||
else if ( i == 2 )
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void SetPointsToLine( Line3 line, int index )
|
||||
{
|
||||
line.Set( GetPoint( index ), GetPoint( ( index + 1 ) % 3 ) );
|
||||
}
|
||||
|
||||
public Line3 GetIntersectionLine( Triangle3 other )
|
||||
{
|
||||
var ownSphere = boundingSphere;
|
||||
var otherSphere = other.boundingSphere;
|
||||
|
||||
if ( ! ownSphere.IntersectsSphere( otherSphere ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var line = new Line3();
|
||||
|
||||
var intersections = new List<Vector3>();
|
||||
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
SetPointsToLine( line, i );
|
||||
var intersection = other.GetIntersection( line );
|
||||
|
||||
if ( intersection != null )
|
||||
{
|
||||
intersections.Add( (Vector3) intersection );
|
||||
}
|
||||
}
|
||||
|
||||
if ( intersections.Count == 2 )
|
||||
{
|
||||
line.Set( intersections[ 0 ], intersections[ 1 ] );
|
||||
return line;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
other.SetPointsToLine( line, i );
|
||||
var intersection = GetIntersection( line );
|
||||
|
||||
if ( intersection != null )
|
||||
{
|
||||
intersections.Add( (Vector3) intersection );
|
||||
}
|
||||
}
|
||||
|
||||
if ( intersections.Count == 2 )
|
||||
{
|
||||
line.Set( intersections[ 0 ], intersections[ 1 ] );
|
||||
return line;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public bool Intersects( Triangle3 other )
|
||||
{
|
||||
var ownSphere = boundingSphere;
|
||||
var otherSphere = other.boundingSphere;
|
||||
|
||||
if ( ! ownSphere.IntersectsSphere( otherSphere ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var line = new Line3();
|
||||
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
if ( PointInside( other.GetPoint( i ) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( other.PointInside( GetPoint( i ) ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SetPointsToLine( line, i );
|
||||
|
||||
if ( other.Intersects( line ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
other.SetPointsToLine( line, i );
|
||||
|
||||
if ( Intersects( line ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static bool InsideTriangle( Vector3 point, Vector3 a, Vector3 b, Vector3 c )
|
||||
{
|
||||
var bary = GetBaryCentricCoordinate( point, a, b, c );
|
||||
|
||||
if ( bary == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var values = (Vector3) bary;
|
||||
|
||||
var insideV = Range.Contains( values.Y, 0, 1 );
|
||||
var insideU = Range.Contains( values.Z, 0, 1 );
|
||||
var insideX = Range.Contains( values.X, 0, 1 );
|
||||
|
||||
var result = insideX && insideV && insideU;
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public static Vector3? GetBaryCentricCoordinate( Vector3 point, Vector3 a, Vector3 b, Vector3 c )
|
||||
{
|
||||
var _v0 = c - a;
|
||||
var _v1 = b - a;
|
||||
var _v2 = point - a;
|
||||
|
||||
var dot00 = Math3D.Dot( _v0, _v0 );
|
||||
var dot01 = Math3D.Dot( _v0, _v1 );
|
||||
var dot02 = Math3D.Dot( _v0, _v2 );
|
||||
var dot11 = Math3D.Dot( _v1, _v1 );
|
||||
var dot12 = Math3D.Dot( _v1, _v2 );
|
||||
|
||||
var denom = ( dot00 * dot11 - dot01 * dot01 );
|
||||
|
||||
if ( denom == 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var invDenom = 1f / denom;
|
||||
|
||||
var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
|
||||
var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
|
||||
|
||||
return new Vector3( 1f - u - v, v, u );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System.Text;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Math2D
|
||||
{
|
||||
public static float Dot( Vector2 a, Vector2 b )
|
||||
{
|
||||
return a.Dot( b );
|
||||
}
|
||||
|
||||
public static Vector2 XZ( Vector3 v )
|
||||
{
|
||||
return new Vector2( v.X, v.Z );
|
||||
}
|
||||
|
||||
public static Vector2 Fract( Vector2 a )
|
||||
{
|
||||
return new Vector2( MathX.Fract( a.X ), MathX.Fract( a.Y ) );
|
||||
}
|
||||
|
||||
public static Vector2 SmoothStep( Vector2 a, Vector2 b, Vector2 t )
|
||||
{
|
||||
var x = MathX.Smoothstep( a.X, b.X, t.X );
|
||||
var y = MathX.Smoothstep( a.Y, b.Y, t.Y );
|
||||
return new Vector2( x, y );
|
||||
}
|
||||
|
||||
public static Vector2 Rotate90DegreesRight( Vector2 v )
|
||||
{
|
||||
// 1, 0.5 => -0.5, 1 : -y, x
|
||||
return new Vector2( -v.Y, v.X );
|
||||
}
|
||||
|
||||
public static Vector2 Rotate90DegreesLeft( Vector2 v )
|
||||
{
|
||||
// -0.5, 1 => 1, 0.5 : y, -x
|
||||
return new Vector2( v.Y, -v.X );
|
||||
}
|
||||
|
||||
public static Vector2 Rotate90Degrees( Vector2 v, bool clockwise )
|
||||
{
|
||||
return clockwise ? Rotate90DegreesRight( v ) : Rotate90DegreesLeft( v );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,8 +6,146 @@ using System;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Math3D
|
||||
public static class Math3D
|
||||
{
|
||||
public static Vector3 OnCircleXZ( float radians, float size = 1 )
|
||||
{
|
||||
var x = Mathf.Cos( radians ) * size;
|
||||
var z = Mathf.Sin( radians ) * size;
|
||||
|
||||
return new Vector3( x, 0, z );
|
||||
}
|
||||
|
||||
public static Vector3 XYasXZ( Vector2 v )
|
||||
{
|
||||
return new Vector3( v.X, 0, v.Y );
|
||||
}
|
||||
|
||||
public static float Dot( Vector3 a, Vector3 b )
|
||||
{
|
||||
return a.Dot( b );
|
||||
}
|
||||
|
||||
public static Vector3 Cross( Vector3 a, Vector3 b )
|
||||
{
|
||||
return a.Cross( b );
|
||||
}
|
||||
|
||||
public static Vector3 Fract( Vector3 a )
|
||||
{
|
||||
return new Vector3( MathX.Fract( a.X ), MathX.Fract( a.Y ), MathX.Fract( a.Z ) );
|
||||
}
|
||||
|
||||
public static bool IsExactlyZero( Vector3 v )
|
||||
{
|
||||
return v.X == 0 && v.Y == 0 && v.Z == 0;
|
||||
}
|
||||
|
||||
public static Vector3 ComputeNormalFast( Vector3 a, Vector3 b, Vector3 c )
|
||||
{
|
||||
return Math3D.Cross( c - b , a - b ).Normalized();
|
||||
}
|
||||
|
||||
public static Vector3 ComputeNormal( Vector3 a, Vector3 b, Vector3 c )
|
||||
{
|
||||
var cross = Math3D.Cross( c - b , a - b );
|
||||
|
||||
if ( Math3D.IsExactlyZero( cross ) )
|
||||
{
|
||||
cross = Math3D.Cross( b - c , a - c );
|
||||
}
|
||||
|
||||
if ( Math3D.IsExactlyZero( cross ) )
|
||||
{
|
||||
cross = Math3D.Cross( c - a , b - a );
|
||||
}
|
||||
|
||||
return cross.Normalized();
|
||||
}
|
||||
|
||||
|
||||
public static Vector3 SmoothStep( Vector3 a, Vector3 b, Vector3 t )
|
||||
{
|
||||
var x = MathX.Smoothstep( a.X, b.X, t.X );
|
||||
var y = MathX.Smoothstep( a.Y, b.Y, t.Y );
|
||||
var z = MathX.Smoothstep( a.Z, b.Z, t.Z );
|
||||
|
||||
return new Vector3( x, y, z );
|
||||
}
|
||||
|
||||
public static Vector3 Center( params Vector3[] points )
|
||||
{
|
||||
var center = Vector3.Zero;
|
||||
|
||||
if ( points.Length == 0 )
|
||||
{
|
||||
return center;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < points.Length; i++ )
|
||||
{
|
||||
center += points[ i ];
|
||||
}
|
||||
|
||||
return center / points.Length;
|
||||
}
|
||||
|
||||
public static Vector3 Center( List<Vector3> points )
|
||||
{
|
||||
var center = Vector3.Zero;
|
||||
|
||||
if ( points.Count == 0 )
|
||||
{
|
||||
return center;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
center += points[ i ];
|
||||
}
|
||||
|
||||
return center / points.Count;
|
||||
}
|
||||
|
||||
public static Vector3 GetClosest( Vector3 from, params Vector3[] points )
|
||||
{
|
||||
var distance = float.MaxValue;
|
||||
var index = -1;
|
||||
|
||||
for ( int i = 0; i < points.Length; i++ )
|
||||
{
|
||||
var d = from.DistanceSquaredTo( points[ i ] );
|
||||
|
||||
if ( d < distance )
|
||||
{
|
||||
index = i;
|
||||
distance = d;
|
||||
}
|
||||
}
|
||||
|
||||
return points[ index ];
|
||||
}
|
||||
|
||||
public static Vector3 GetClosest( Vector3 from, List<Vector3> points )
|
||||
{
|
||||
var distance = float.MaxValue;
|
||||
var index = -1;
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
var d = from.DistanceSquaredTo( points[ i ] );
|
||||
|
||||
if ( d < distance )
|
||||
{
|
||||
index = i;
|
||||
distance = d;
|
||||
}
|
||||
}
|
||||
|
||||
return points[ index ];
|
||||
}
|
||||
|
||||
|
||||
public static Vector3 LerpUnclamped( Vector3 a, Vector3 b, float amount )
|
||||
{
|
||||
return a + amount * ( b - a );
|
||||
|
@ -18,12 +156,115 @@ namespace Rokojori
|
|||
return LerpUnclamped( a, b, MathX.Clamp01( amount ) );
|
||||
}
|
||||
|
||||
public static Quaternion GetGlobalRotation( Node3D node )
|
||||
public static Quaternion GetGlobalQuaternion( this Node3D node )
|
||||
{
|
||||
return node.GlobalBasis.GetRotationQuaternion();
|
||||
return GetGlobalRotationFrom( node );
|
||||
}
|
||||
|
||||
public static void SetGlobalRotation( Node3D node, Quaternion quaternion )
|
||||
public static Quaternion GetGlobalRotationFrom( Node3D node )
|
||||
{
|
||||
var quaternion = node.GlobalBasis.GetRotationQuaternion();
|
||||
|
||||
return quaternion;
|
||||
}
|
||||
|
||||
public static Vector3 MinPosition( Node3D a, Node3D b )
|
||||
{
|
||||
return a.GlobalPosition.Min( b.GlobalPosition );
|
||||
}
|
||||
|
||||
public static Vector3 MaxPosition( Node3D a, Node3D b )
|
||||
{
|
||||
return a.GlobalPosition.Max( b.GlobalPosition );
|
||||
}
|
||||
|
||||
public static Vector3 SnapRounded( Vector3 v, Vector3 snapping )
|
||||
{
|
||||
v.X = MathX.SnapRounded( v.X, snapping.X );
|
||||
v.Y = MathX.SnapRounded( v.Y, snapping.Y );
|
||||
v.Z = MathX.SnapRounded( v.Z, snapping.Z );
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static Vector3 SnapCeiled( Vector3 v, Vector3 snapping )
|
||||
{
|
||||
v.X = MathX.SnapCeiled( v.X, snapping.X );
|
||||
v.Y = MathX.SnapCeiled( v.Y, snapping.Y );
|
||||
v.Z = MathX.SnapCeiled( v.Z, snapping.Z );
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static Vector3 SnapFloored( Vector3 v, Vector3 snapping )
|
||||
{
|
||||
v.X = MathX.SnapFloored( v.X, snapping.X );
|
||||
v.Y = MathX.SnapFloored( v.Y, snapping.Y );
|
||||
v.Z = MathX.SnapFloored( v.Z, snapping.Z );
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static Quaternion AlignUp( Quaternion rotation, Vector3 upDirection )
|
||||
{
|
||||
var basis = new Basis( rotation );
|
||||
var aligned = AlignUp( basis, upDirection );
|
||||
return aligned.GetRotationQuaternion();
|
||||
}
|
||||
|
||||
public static Basis AlignUp( Basis basis, Vector3 upDirection )
|
||||
{
|
||||
basis.Y = upDirection;
|
||||
basis.X = - basis.Z.Cross( upDirection );
|
||||
return basis.Orthonormalized();
|
||||
}
|
||||
|
||||
public static Vector3 Lerp( Vector3 a, Vector3 b, float lerp )
|
||||
{
|
||||
return a.Lerp( b, lerp );
|
||||
}
|
||||
|
||||
public static Quaternion LookRotation( Vector3 direction, Vector3 up )
|
||||
{
|
||||
if ( direction.Length() == 0 )
|
||||
{
|
||||
return Quaternion.Identity;
|
||||
}
|
||||
|
||||
var t = new Transform3D();
|
||||
t.Basis = Basis.Identity;
|
||||
t.Origin = Vector3.Zero;
|
||||
|
||||
t = t.LookingAt( direction, up );
|
||||
|
||||
return t.Basis.GetRotationQuaternion();
|
||||
}
|
||||
|
||||
public static Vector3 LerpComponents( Vector3 a, Vector3 b, Vector3 t )
|
||||
{
|
||||
return new Vector3( Mathf.Lerp( a.X, b.X, t.X ), Mathf.Lerp( a.Y, b.Y, t.Y ), Mathf.Lerp( a.Z, b.Z, t.Z ) );
|
||||
}
|
||||
|
||||
public static Vector4 AsVector4( this Quaternion q)
|
||||
{
|
||||
return new Vector4( q.X, q.Y, q.Z, q.W );
|
||||
}
|
||||
|
||||
public static void SetGlobalQuaternion( this Node3D node, Quaternion quaternion )
|
||||
{
|
||||
var offset = node.GlobalPosition;
|
||||
|
||||
var localScale = node.Scale;
|
||||
node.GlobalBasis = new Basis( quaternion );
|
||||
node.GlobalPosition = offset;
|
||||
node.Scale = localScale;
|
||||
|
||||
|
||||
|
||||
//SetGlobalRotationTo( node, quaternion );
|
||||
}
|
||||
|
||||
public static void SetGlobalRotationTo( Node3D node, Quaternion quaternion )
|
||||
{
|
||||
var forward = quaternion * Vector3.Forward;
|
||||
var up = quaternion * Vector3.Up;
|
||||
|
@ -31,16 +272,62 @@ namespace Rokojori
|
|||
node.LookAt( node.GlobalPosition + forward, up );
|
||||
}
|
||||
|
||||
public static void LookTowards( this Node3D node, Vector3 forwardDirection, Vector3 upDirection, Quaternion rotation )
|
||||
{
|
||||
//forwardDirection = rotation * forwardDirection;
|
||||
//upDirection = rotation * upDirection;
|
||||
|
||||
node.LookTowards( forwardDirection, upDirection );
|
||||
node.SetGlobalQuaternion( node.GetGlobalQuaternion() * rotation );
|
||||
}
|
||||
|
||||
public static void LookTowards( this Node3D node, Vector3 forward, Vector3 up )
|
||||
{
|
||||
node.LookAt( forward + node.GlobalPosition, up );
|
||||
}
|
||||
|
||||
|
||||
public static Quaternion GetDifference( this Quaternion q, Quaternion other )
|
||||
{
|
||||
return GetQuaternionDifference( q, other );
|
||||
}
|
||||
|
||||
public static Quaternion GetQuaternionDifference( Quaternion a, Quaternion b )
|
||||
{
|
||||
return b.Inverse() * a;
|
||||
}
|
||||
|
||||
public static Quaternion GetQuaternionFraction( Quaternion q, float fraction )
|
||||
{
|
||||
return Quaternion.Identity.Slerp( q, fraction );
|
||||
}
|
||||
|
||||
|
||||
public static Vector3 GlobalForward( this Node3D node )
|
||||
{
|
||||
return GetGlobalForward( node );
|
||||
}
|
||||
|
||||
public static Vector3 GetGlobalForward( Node3D node )
|
||||
{
|
||||
return -node.GlobalBasis.Z;
|
||||
}
|
||||
|
||||
public static Vector3 GlobalUp( this Node3D node )
|
||||
{
|
||||
return GetGlobalUp( node );
|
||||
}
|
||||
|
||||
public static Vector3 GetGlobalUp( Node3D node )
|
||||
{
|
||||
return node.GlobalBasis.Y;
|
||||
}
|
||||
|
||||
public static Vector3 GlobalRight( this Node3D node )
|
||||
{
|
||||
return GetGlobalRight( node );
|
||||
}
|
||||
|
||||
public static Vector3 GetGlobalRight( Node3D node )
|
||||
{
|
||||
return node.GlobalBasis.X;
|
||||
|
@ -63,6 +350,54 @@ namespace Rokojori
|
|||
|
||||
return right.Normalized();
|
||||
}
|
||||
|
||||
public static void SetGlobalX( this Node3D node, float x )
|
||||
{
|
||||
var gp = node.GlobalPosition;
|
||||
|
||||
gp.X = x;
|
||||
|
||||
node.GlobalPosition = gp;
|
||||
}
|
||||
|
||||
public static void SetGlobalY( this Node3D node, float y )
|
||||
{
|
||||
var gp = node.GlobalPosition;
|
||||
|
||||
gp.Y = y;
|
||||
|
||||
node.GlobalPosition = gp;
|
||||
}
|
||||
|
||||
public static void SetGlobalZ( this Node3D node, float z )
|
||||
{
|
||||
var gp = node.GlobalPosition;
|
||||
|
||||
gp.Z = z;
|
||||
|
||||
node.GlobalPosition = gp;
|
||||
}
|
||||
|
||||
public static Aabb? GetWorldBounds( this Node3D node )
|
||||
{
|
||||
return GetWorldBoundsFrom( node );
|
||||
}
|
||||
|
||||
public static Aabb? GetWorldBoundsFrom( Node3D node )
|
||||
{
|
||||
Aabb? worldBounds = null;
|
||||
|
||||
Nodes.ForEach<VisualInstance3D>( node,
|
||||
( vi )=>
|
||||
{
|
||||
var nBounds = vi.GetAabb();
|
||||
|
||||
worldBounds = worldBounds == null ? nBounds : ( ((Aabb)worldBounds).Merge( nBounds ) );
|
||||
}
|
||||
);
|
||||
|
||||
return worldBounds;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,103 @@ namespace Rokojori
|
|||
{
|
||||
public const float fps120Delta = 1/120f;
|
||||
|
||||
public static float Min( params float[] values )
|
||||
{
|
||||
var value = - float.MaxValue;
|
||||
|
||||
for ( int i = 0; i < values.Length; i++ )
|
||||
{
|
||||
value = Mathf.Min( values[ i ], value );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float Max( params float[] values )
|
||||
{
|
||||
var value = - float.MaxValue;
|
||||
|
||||
for ( int i = 0; i < values.Length; i++ )
|
||||
{
|
||||
value = Mathf.Max( values[ i ], value );
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float Sample( float tl, float tr, float bl, float br, Vector2 uv )
|
||||
{
|
||||
return Mathf.Lerp( tl, tr, uv.X ) +
|
||||
( bl - tl ) * uv.Y * ( 1.0f - uv.X ) +
|
||||
( br - tr ) * uv.X * uv.Y;
|
||||
}
|
||||
|
||||
public static float Sample(
|
||||
float ba, float bb, float bc, float bd,
|
||||
float ta, float tb, float tc, float td,
|
||||
Vector3 uvw
|
||||
)
|
||||
{
|
||||
var bottom = Sample( ba, bb, bc, bd, new Vector2( uvw.X, uvw.Y ) );
|
||||
var top = Sample( ta, tb, tc, td, new Vector2( uvw.X, uvw.Y ) );
|
||||
|
||||
return Mathf.Lerp( bottom, top, uvw.Z );
|
||||
}
|
||||
|
||||
public static float Fract( float value )
|
||||
{
|
||||
return value - Mathf.Floor( value );
|
||||
}
|
||||
|
||||
public static float TimeLerpAmountExp( float t, float time )
|
||||
{
|
||||
return Mathf.Exp( -t * time );
|
||||
}
|
||||
|
||||
public static float TimeLerp( float lastValue, float nextValue, float t, float time )
|
||||
{
|
||||
return Mathf.Lerp( nextValue, lastValue, TimeLerpAmountExp( t, time ) );
|
||||
}
|
||||
|
||||
public static float AbsoluteDeltaAngle( float degreesA, float degreesB )
|
||||
{
|
||||
return Mathf.Abs( AngleDelta( degreesA, degreesB ) );
|
||||
}
|
||||
|
||||
public static float Smoothstep ( float edge0, float edge1, float x )
|
||||
{
|
||||
x = MathX.Clamp01( ( x - edge0 ) / ( edge1 - edge0 ) );
|
||||
|
||||
return x * x * ( 3.0f - 2.0f * x );
|
||||
}
|
||||
|
||||
public static float SnapRounded( float value, float snappingDistance )
|
||||
{
|
||||
return Mathf.Round( value / snappingDistance ) * snappingDistance;
|
||||
}
|
||||
|
||||
public static float SnapCeiled( float value, float snappingDistance )
|
||||
{
|
||||
return Mathf.Ceil( value / snappingDistance ) * snappingDistance;
|
||||
}
|
||||
|
||||
public static float SnapFloored( float value, float snappingDistance )
|
||||
{
|
||||
return Mathf.Floor( value / snappingDistance ) * snappingDistance;
|
||||
}
|
||||
|
||||
public static float AngleDelta( float degreesA, float degreesB)
|
||||
{
|
||||
var angleDelta = degreesB - degreesA;
|
||||
angleDelta = (angleDelta + 180f) % 360f - 180f;
|
||||
return angleDelta;
|
||||
}
|
||||
|
||||
static float CustomModulo( float a, float n )
|
||||
{
|
||||
return a - Mathf.Floor( a / n ) * n;
|
||||
}
|
||||
|
||||
public static float Clamp01( float value )
|
||||
{
|
||||
return Mathf.Clamp( value, 0, 1 );
|
||||
|
@ -225,10 +322,7 @@ namespace Rokojori
|
|||
}
|
||||
|
||||
|
||||
public static float TimeLerp( float from, float to, float t, float timeDelta )
|
||||
{
|
||||
return Mathf.Lerp( from, to, 1f - Mathf.Pow( t, timeDelta ) );
|
||||
}
|
||||
|
||||
|
||||
public static float PolarAxis( bool negative, bool positive )
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ Replace: $1.DistanceTo(
|
|||
Match: \.x
|
||||
Replace: .X
|
||||
|
||||
Match: \.Y
|
||||
Match: \.y
|
||||
Replace: .Y
|
||||
|
||||
Match: \.z
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class NavigationMap2D
|
||||
{
|
||||
public Rid map;
|
||||
public Rid region;
|
||||
|
||||
public Vector2[] GetPath( Vector2 start, Vector2 end )
|
||||
{
|
||||
return NavigationServer2D.MapGetPath( map, start, end, true );
|
||||
}
|
||||
|
||||
public static async Task<NavigationMap2D> Create( Node node, List<Path2> regions )
|
||||
{
|
||||
var map = NavigationServer2D.MapCreate();
|
||||
NavigationServer2D.MapSetActive( map, true );
|
||||
|
||||
var cellSize = NavigationServer2D.MapGetCellSize( map );
|
||||
|
||||
|
||||
var region = NavigationServer2D.RegionCreate();
|
||||
NavigationServer2D.RegionSetTransform( region, Transform2D.Identity );
|
||||
|
||||
NavigationServer2D.RegionSetMap( region, map );
|
||||
|
||||
var polygon = new NavigationPolygon();
|
||||
// polygon.SetCe
|
||||
for ( int i = 0; i < 1 && i < regions.Count; i++ )
|
||||
{
|
||||
regions[ i ].AddToNavigationPolygon( polygon );
|
||||
}
|
||||
|
||||
NavigationServer2D.RegionSetNavigationPolygon( region, polygon );
|
||||
|
||||
await node.ToSignal( node.GetTree(), SceneTree.SignalName.PhysicsFrame );
|
||||
|
||||
var mapData = new NavigationMap2D();
|
||||
|
||||
mapData.map = map;
|
||||
mapData.region = region;
|
||||
|
||||
|
||||
return mapData;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Godot.Collections;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -15,6 +16,47 @@ namespace Rokojori
|
|||
public Rid rid;
|
||||
|
||||
|
||||
public static bool HasCollisionMask( Node n )
|
||||
{
|
||||
return n is CsgShape3D || n is CollisionObject3D;
|
||||
}
|
||||
|
||||
public static uint GetCollisionMask( Node n )
|
||||
{
|
||||
if ( n is CsgShape3D )
|
||||
{
|
||||
return ( n as CsgShape3D ).CollisionMask;
|
||||
}
|
||||
|
||||
if ( n is CollisionObject3D )
|
||||
{
|
||||
return ( n as CollisionObject3D ).CollisionMask;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool HasCollisionLayer( Node n )
|
||||
{
|
||||
return n is CsgShape3D || n is CollisionObject3D;
|
||||
}
|
||||
|
||||
public static uint GetCollisionLayer( Node n )
|
||||
{
|
||||
if ( n is CsgShape3D )
|
||||
{
|
||||
return ( n as CsgShape3D ).CollisionLayer;
|
||||
}
|
||||
|
||||
if ( n is CollisionObject3D )
|
||||
{
|
||||
return ( n as CollisionObject3D ).CollisionLayer;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public void Get( PhysicsRayQueryParameters3D ray, PhysicsDirectSpaceState3D physicsState )
|
||||
{
|
||||
var result = physicsState.IntersectRay( ray );
|
||||
|
@ -40,5 +82,96 @@ namespace Rokojori
|
|||
// RJLog.Log( "Has Collision:", HierarchyName.Of( collider ), ">> at position:", position, "with normal:", normal );
|
||||
|
||||
}
|
||||
|
||||
public static CollisionData FindCollision( World3D world, PhysicsRayQueryParameters3D rayParameters, Func<CollisionData,bool> predicate )
|
||||
{
|
||||
var physics = world.DirectSpaceState;
|
||||
|
||||
var excludes = new Array<Rid>();
|
||||
|
||||
var maxHits = 10000;
|
||||
|
||||
for ( int i = 0; i < maxHits; i++ )
|
||||
{
|
||||
rayParameters.Exclude = excludes;
|
||||
|
||||
var collisionData = new CollisionData();
|
||||
collisionData.Get( rayParameters, physics );
|
||||
|
||||
if ( ! collisionData.hasCollision )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( predicate( collisionData ) )
|
||||
{
|
||||
return collisionData;
|
||||
}
|
||||
|
||||
excludes.Add( collisionData.rid );
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public static int MultiRayCast( World3D world, PhysicsRayQueryParameters3D rayParameters, List<CollisionData> collisionsOutput )
|
||||
{
|
||||
var physics = world.DirectSpaceState;
|
||||
|
||||
var excludes = new Array<Rid>();
|
||||
|
||||
var numCollisions = 0;
|
||||
|
||||
for ( int i = 0; i < collisionsOutput.Count; i++ )
|
||||
{
|
||||
rayParameters.Exclude = excludes;
|
||||
|
||||
var collisionData = collisionsOutput[ i ];
|
||||
collisionData.Get( rayParameters, physics );
|
||||
|
||||
if ( ! collisionData.hasCollision )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
excludes.Add( collisionData.rid );
|
||||
|
||||
numCollisions ++;
|
||||
}
|
||||
|
||||
return numCollisions;
|
||||
|
||||
}
|
||||
|
||||
public static List<CollisionData> MultiRayCast( World3D world, PhysicsRayQueryParameters3D rayParameters, int maxHits = 100 )
|
||||
{
|
||||
var physics = world.DirectSpaceState;
|
||||
|
||||
var excludes = new Array<Rid>();
|
||||
|
||||
var collisions = new List<CollisionData>();
|
||||
|
||||
for ( int i = 0; i < maxHits; i++ )
|
||||
{
|
||||
rayParameters.Exclude = excludes;
|
||||
|
||||
var collisionData = new CollisionData();
|
||||
collisionData.Get( rayParameters, physics );
|
||||
|
||||
if ( ! collisionData.hasCollision )
|
||||
{
|
||||
return collisions;
|
||||
}
|
||||
|
||||
excludes.Add( collisionData.rid );
|
||||
|
||||
collisions.Add( collisionData );
|
||||
}
|
||||
|
||||
return collisions;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ConnectionCircle:Node3D
|
||||
#if TOOLS
|
||||
, GizmoDrawer
|
||||
#endif
|
||||
{
|
||||
[Export]
|
||||
public bool updateAlways = false;
|
||||
|
||||
[Export]
|
||||
public Node3D root;
|
||||
|
||||
[Export]
|
||||
public float radius = 1;
|
||||
float _radius = -1;
|
||||
|
||||
[Export( PropertyHint.Range, "2,64") ]
|
||||
public int divisions = 16;
|
||||
int _divisions = -1;
|
||||
|
||||
[Export]
|
||||
public float editorGizmoSize = 1;
|
||||
|
||||
float _editorGizmoSize = 1;
|
||||
|
||||
public Pose GetLocalPose( int index )
|
||||
{
|
||||
var p = new Pose();
|
||||
var state = index / (float)( divisions );
|
||||
var radians = state * Mathf.Pi * 2f;
|
||||
var angle = Mathf.RadToDeg( radians );
|
||||
|
||||
p.rotation = Quaternion.FromEuler( new Vector3( 0, -radians , 0 ) );
|
||||
p.position = p.rotation * Vector3.Forward * radius;
|
||||
|
||||
// RJLog.Log( radians, angle, p.rotation, p.position );
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public Pose GetGlobalPose( int index )
|
||||
{
|
||||
return GetLocalPose( index ).ToGlobal( this );
|
||||
}
|
||||
|
||||
#if TOOLS
|
||||
|
||||
|
||||
public void DrawGizmo( EditorNode3DGizmoPlugin gizmoPlugin, EditorNode3DGizmo gizmo )
|
||||
{
|
||||
gizmo.Clear();
|
||||
|
||||
|
||||
var material = gizmoPlugin.GetMaterial( "main", gizmo );
|
||||
|
||||
for ( int i = 0; i < divisions; i++ )
|
||||
{
|
||||
var p = GetLocalPose( i );
|
||||
|
||||
var center = p.position;
|
||||
var up = p.position + p.up * editorGizmoSize;
|
||||
var forward = p.position + p.forward * editorGizmoSize;
|
||||
var right = p.position + p.right * radius * 4f / divisions;
|
||||
var left = p.position - p.right * radius * 4f / divisions;
|
||||
|
||||
/*gizmo.AddLines( new Vector3[]
|
||||
{
|
||||
center, forward
|
||||
},
|
||||
material
|
||||
);*/
|
||||
|
||||
gizmo.AddLines( new Vector3[]
|
||||
{
|
||||
center, up,
|
||||
center, forward,
|
||||
right, left,
|
||||
right, forward,
|
||||
left, forward,
|
||||
up, forward
|
||||
|
||||
},
|
||||
material
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
var changed = false;
|
||||
|
||||
if ( editorGizmoSize != _editorGizmoSize ||
|
||||
radius != _radius ||
|
||||
divisions != _divisions
|
||||
)
|
||||
{
|
||||
_editorGizmoSize = editorGizmoSize;
|
||||
_radius = radius;
|
||||
_divisions = divisions;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ( changed )
|
||||
{
|
||||
UpdateGizmos();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ConnectionPin:Node3D
|
||||
#if TOOLS
|
||||
, GizmoDrawer
|
||||
#endif
|
||||
{
|
||||
[Export]
|
||||
public bool updateAlways = false;
|
||||
|
||||
[Export]
|
||||
public Node3D root;
|
||||
|
||||
[Export]
|
||||
public bool moveToMinX = false;
|
||||
|
||||
[Export]
|
||||
public bool moveToMaxX = false;
|
||||
|
||||
[Export]
|
||||
public bool moveToMinY = false;
|
||||
|
||||
[Export]
|
||||
public bool moveToMaxY = false;
|
||||
|
||||
[Export]
|
||||
public bool moveToMinZ = false;
|
||||
|
||||
[Export]
|
||||
public bool moveToMaxZ = false;
|
||||
|
||||
[Export]
|
||||
public float editorGizmoSize = 1;
|
||||
|
||||
float _editorGizmoSize = 1;
|
||||
|
||||
|
||||
#if TOOLS
|
||||
|
||||
|
||||
public void DrawGizmo( EditorNode3DGizmoPlugin gizmoPlugin, EditorNode3DGizmo gizmo )
|
||||
{
|
||||
gizmo.Clear();
|
||||
|
||||
var center = Vector3.Zero;
|
||||
var up = Vector3.Up * editorGizmoSize;
|
||||
var forward = Vector3.Forward * editorGizmoSize;
|
||||
var right = Vector3.Right * editorGizmoSize;
|
||||
|
||||
var material = gizmoPlugin.GetMaterial( "main", gizmo );
|
||||
|
||||
gizmo.AddLines(
|
||||
new Vector3[]
|
||||
{
|
||||
center, up,
|
||||
center, -forward,
|
||||
center, right,
|
||||
center, -right,
|
||||
right, -forward,
|
||||
-right, -forward,
|
||||
up, -forward,
|
||||
up, -right,
|
||||
up, right
|
||||
},
|
||||
material
|
||||
);
|
||||
}
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
var changed = false;
|
||||
|
||||
if ( editorGizmoSize != _editorGizmoSize )
|
||||
{
|
||||
_editorGizmoSize = editorGizmoSize;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if ( changed )
|
||||
{
|
||||
UpdateGizmos();
|
||||
}
|
||||
|
||||
if ( ! ( moveToMinX || moveToMaxX || moveToMinY || moveToMaxY || moveToMinZ || moveToMaxZ ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( root == null )
|
||||
{
|
||||
RJLog.Log( "No Root!" );
|
||||
ClearFlags();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var optionalBbounds = root.GetWorldBounds();
|
||||
|
||||
if ( optionalBbounds == null )
|
||||
{
|
||||
RJLog.Log( "No Bounds!" );
|
||||
ClearFlags();
|
||||
return;
|
||||
}
|
||||
|
||||
var bounds = (Aabb) optionalBbounds;
|
||||
|
||||
if ( moveToMinX || moveToMaxX )
|
||||
{
|
||||
this.SetGlobalX( ( moveToMinX ? bounds.Position : bounds.End ).X );
|
||||
}
|
||||
|
||||
if ( moveToMinY || moveToMaxY )
|
||||
{
|
||||
this.SetGlobalY( ( moveToMinY ? bounds.Position : bounds.End ).Y );
|
||||
}
|
||||
|
||||
if ( moveToMinZ || moveToMaxZ )
|
||||
{
|
||||
this.SetGlobalZ( ( moveToMinZ ? bounds.Position : bounds.End ).Z );
|
||||
}
|
||||
|
||||
ClearFlags();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ClearFlags()
|
||||
{
|
||||
moveToMinX = false;
|
||||
moveToMaxX = false;
|
||||
|
||||
moveToMinY = false;
|
||||
moveToMaxY = false;
|
||||
|
||||
moveToMinZ = false;
|
||||
moveToMaxZ = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
public static readonly Quaternion YawFlipRotation = Quaternion.FromEuler( new Vector3( 0, 180, 0 ) / 180 * Mathf.Pi );
|
||||
|
||||
public static void Connect( Node3D target, Node3D targetPin, Node3D sourcePin )
|
||||
{
|
||||
var targetRotation = target.GetGlobalQuaternion();
|
||||
var targetPinRotation = targetPin.GetGlobalQuaternion();
|
||||
|
||||
var pinToParent = targetPinRotation.GetDifference( targetRotation );
|
||||
|
||||
var forward = sourcePin.GlobalForward();
|
||||
var up = sourcePin.GlobalUp();
|
||||
|
||||
var rotation = ConnectionPin.YawFlipRotation * pinToParent;
|
||||
|
||||
target.LookTowards( forward, up, rotation );
|
||||
|
||||
var offset = ( sourcePin.GlobalPosition - targetPin.GlobalPosition );
|
||||
target.GlobalTranslate( offset );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ConnectionPinTester:Node3D
|
||||
{
|
||||
[Export]
|
||||
public ConnectionPin fromPin;
|
||||
|
||||
[Export]
|
||||
public Node3D toParent;
|
||||
[Export]
|
||||
public ConnectionPin toPin;
|
||||
|
||||
[Export]
|
||||
public bool update = false;
|
||||
|
||||
[Export]
|
||||
public bool updateAlways = false;
|
||||
|
||||
[Export]
|
||||
public Vector3 eulerRotation;
|
||||
|
||||
[Export]
|
||||
public bool diff_reverse = false;
|
||||
|
||||
[Export]
|
||||
public bool mult_reverse = false;
|
||||
|
||||
[Export]
|
||||
public Vector4 targetPin;
|
||||
|
||||
[Export]
|
||||
public Vector4 currentPin;
|
||||
|
||||
[Export]
|
||||
public Vector4 needed;
|
||||
|
||||
[Export]
|
||||
public Vector4 oldApplying;
|
||||
|
||||
[Export]
|
||||
public Vector4 applyingTargetApplied;
|
||||
|
||||
|
||||
[Export]
|
||||
public Vector4 pinApplyied;
|
||||
|
||||
[Export]
|
||||
public Node3D applyingTarget;
|
||||
|
||||
[Export]
|
||||
public Node3D forwardTarget;
|
||||
|
||||
[Export]
|
||||
public Vector3 customRotationEulers;
|
||||
|
||||
[Export]
|
||||
public bool rotateBefore;
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
Connect3();
|
||||
}
|
||||
|
||||
void Connect3()
|
||||
{
|
||||
if ( ! ( update || updateAlways ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
update = false;
|
||||
|
||||
ConnectionPin.Connect( toParent, toPin, fromPin );
|
||||
}
|
||||
|
||||
void Connect2()
|
||||
{
|
||||
if ( ! ( update || updateAlways ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
update = false;
|
||||
|
||||
|
||||
var targetRotation = fromPin.GetGlobalQuaternion();
|
||||
var currentPinRotation = toPin.GetGlobalQuaternion();
|
||||
var parentRotation = applyingTarget.GetGlobalQuaternion();
|
||||
|
||||
|
||||
var pinToParent = diff_reverse ?
|
||||
Math3D.GetQuaternionDifference( currentPinRotation, parentRotation ) :
|
||||
Math3D.GetQuaternionDifference( parentRotation, currentPinRotation );
|
||||
|
||||
|
||||
|
||||
var forward = fromPin.GlobalForward();
|
||||
var up = fromPin.GlobalUp();
|
||||
|
||||
var customRotation = Quaternion.FromEuler( customRotationEulers / 180 * Mathf.Pi ) * pinToParent;
|
||||
|
||||
forwardTarget.GlobalPosition = applyingTarget.GlobalPosition + forward;
|
||||
|
||||
targetPin = targetRotation.AsVector4();
|
||||
currentPin = currentPinRotation.AsVector4();
|
||||
needed = pinToParent.AsVector4();
|
||||
oldApplying = parentRotation.AsVector4();
|
||||
applyingTargetApplied = Vector4.One * -1;
|
||||
pinApplyied = Vector4.One * -1;
|
||||
|
||||
applyingTarget.LookTowards( forward, up, customRotation );
|
||||
|
||||
var offset = ( fromPin.GlobalPosition - toPin.GlobalPosition );
|
||||
applyingTarget.GlobalTranslate( offset );
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Connect()
|
||||
{
|
||||
if ( ! ( update || updateAlways ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
update = false;
|
||||
|
||||
var eulerRads = eulerRotation / 180 * Mathf.Pi;
|
||||
|
||||
var targetRotation = fromPin.GetGlobalQuaternion();
|
||||
|
||||
var currentRotation = toPin.GetGlobalQuaternion();
|
||||
|
||||
|
||||
|
||||
//toPin.SetGlobalQuaternion( targetRotation );
|
||||
|
||||
var neededRotation = diff_reverse ?
|
||||
Math3D.GetQuaternionDifference( currentRotation, targetRotation ) :
|
||||
Math3D.GetQuaternionDifference( targetRotation, currentRotation );
|
||||
|
||||
|
||||
var oldRotation = applyingTarget.GetGlobalQuaternion();
|
||||
|
||||
var resultRotation = mult_reverse ? neededRotation * currentRotation :
|
||||
oldRotation * neededRotation;
|
||||
|
||||
var pinResultRotation = mult_reverse ? neededRotation * currentRotation :
|
||||
currentRotation * neededRotation;
|
||||
|
||||
RJLog.Log(
|
||||
"Target:", targetRotation, "\n",
|
||||
"Current:", currentRotation, "\n",
|
||||
"Needed:", neededRotation, "\n",
|
||||
"OldRotation:", oldRotation, "\n",
|
||||
"Applied:", resultRotation,"\n",
|
||||
"Pin:", pinResultRotation
|
||||
);
|
||||
|
||||
targetPin = targetRotation.AsVector4();
|
||||
currentPin = currentRotation.AsVector4();
|
||||
needed = neededRotation.AsVector4();
|
||||
oldApplying = oldRotation.AsVector4();
|
||||
applyingTargetApplied = resultRotation.AsVector4();
|
||||
pinApplyied = pinResultRotation.AsVector4();
|
||||
|
||||
applyingTarget.SetGlobalQuaternion( resultRotation );
|
||||
|
||||
|
||||
|
||||
//var positionOffset = fromPin.GlobalPosition - toPin.GlobalPosition;
|
||||
|
||||
//toParent.GlobalPosition += positionOffset;
|
||||
|
||||
//toPin.SetGlobalQuaternion( currentRotation * neededRotation );
|
||||
//Math3D.SetGlobalRotation( toPin, targetRotation );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass, Icon("res://Scripts/Rokojori/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 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();
|
||||
|
||||
var linePoints = new List<Vector3>();
|
||||
|
||||
int resolution = editorResolution <= 0 ? 20 : editorResolution;
|
||||
|
||||
renderedResolution = editorResolution;
|
||||
|
||||
var lastPoint = ToLocal( curve.SampleAt( 0 ) );
|
||||
|
||||
for ( int i = 1; i < resolution; i++ )
|
||||
{
|
||||
var t = i / (float) (resolution - 1 );
|
||||
var point = ToLocal( curve.SampleAt( 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;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum SplinePointTangentMode
|
||||
{
|
||||
Automatic,
|
||||
Custom
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class Tangent
|
||||
{
|
||||
[Export]
|
||||
public Node3D node3D;
|
||||
[Export( PropertyHint.Range, "0,2" )]
|
||||
public float weight = 0.5f;
|
||||
}
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class SplinePoint : Node3D
|
||||
#if TOOLS
|
||||
, GizmoDrawerWithHandles
|
||||
#endif
|
||||
|
||||
{
|
||||
|
||||
#if TOOLS
|
||||
|
||||
public void DrawGizmo( EditorNode3DGizmoPlugin gizmoPlugin, EditorNode3DGizmo gizmo )
|
||||
{
|
||||
gizmo.Clear();
|
||||
|
||||
|
||||
var mesh = new SphereMesh();
|
||||
var size = 0.1f;
|
||||
mesh.Radius = size;
|
||||
mesh.Height = size * 2f;
|
||||
|
||||
var transform = new Transform3D();
|
||||
transform.Basis = Basis.Identity;
|
||||
transform.Origin = Vector3.Zero;
|
||||
|
||||
var material = gizmoPlugin.GetMaterial( "main", gizmo );
|
||||
|
||||
|
||||
gizmo.AddMesh( mesh, material, transform );
|
||||
|
||||
gizmo.AddHandles( new Vector3[]{ Vector3.Zero }, material, new int[]{} );
|
||||
|
||||
}
|
||||
|
||||
public string GetHandleName( EditorNode3DGizmo gizmo, int handleId, bool secondary )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
Vector3 startDragPosition = Vector3.Zero;
|
||||
public Variant GetHandleValue( EditorNode3DGizmo gizmo, int handleId, bool secondary )
|
||||
{
|
||||
startDragPosition = GlobalPosition;
|
||||
return Variant.From( GlobalPosition );
|
||||
}
|
||||
|
||||
public void SetHandle( EditorNode3DGizmo gizmo, int id, bool secondary, Camera3D camera, Vector2 point )
|
||||
{
|
||||
var xzPlane = new Plane( Vector3.Up, startDragPosition);
|
||||
var cameraDirection = camera.ProjectLocalRayNormal( point );
|
||||
var intersection = xzPlane.IntersectsRay( camera.GlobalPosition, cameraDirection );
|
||||
|
||||
if ( intersection == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GlobalPosition = (Vector3) intersection;
|
||||
|
||||
}
|
||||
|
||||
public void CommitHandle( EditorNode3DGizmo gizmo, int id, bool secondary, Variant restore, bool cancel )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[Export]
|
||||
public SplinePointTangentMode tangentMode;
|
||||
|
||||
[Export]
|
||||
public Node3D tangentBefore;
|
||||
[Export( PropertyHint.Range, "0,2" )]
|
||||
public float tangentBeforeWeight = 1;
|
||||
|
||||
[Export]
|
||||
public Node3D tangentNext;
|
||||
[Export( PropertyHint.Range, "0,2" )]
|
||||
public float tangentNextWeight = 1;
|
||||
|
||||
[Export( PropertyHint.Range, "0,1")]
|
||||
public float overshootPrevention = 0.5f;
|
||||
|
||||
[Export( PropertyHint.Range, "0,3")]
|
||||
public float tangentScale = 1f;
|
||||
|
||||
[Export( PropertyHint.Range, "0,1")]
|
||||
public float symmetricTangentLength = 0f;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum DiscardMode
|
||||
{
|
||||
DiscardOutside,
|
||||
DiscardInside
|
||||
}
|
||||
|
||||
public enum DiscardBooleanCombinator
|
||||
{
|
||||
Overwrite,
|
||||
UseOperator
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum DiscardNoiseOwnPositionMode
|
||||
{
|
||||
Ignore,
|
||||
Add_Global,
|
||||
Add_Local
|
||||
}
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class DiscardNoise:Discarder
|
||||
{
|
||||
[Export(PropertyHint.Range, "0,1")]
|
||||
public float insideTreshold = 0.5f;
|
||||
|
||||
[Export]
|
||||
public float noiseScale = 1;
|
||||
|
||||
[Export]
|
||||
public Vector3 noiseOffset = Vector3.Zero;
|
||||
|
||||
[Export]
|
||||
public ScattererOwnPositionMode ownPositionMode = ScattererOwnPositionMode.Ignore;
|
||||
|
||||
public override bool IsInside( Vector3 position )
|
||||
{
|
||||
var offset = noiseOffset + ScattererOwnPosition.ComputeOffset( ownPositionMode, this );
|
||||
|
||||
var value = Noise.Perlin( ( position - offset ) * noiseScale );
|
||||
|
||||
return value < insideTreshold;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class DiscardSphere:Discarder
|
||||
{
|
||||
[Export]
|
||||
public float radius;
|
||||
|
||||
public override bool IsInside( Vector3 position )
|
||||
{
|
||||
var localPoint = ToLocal( position );
|
||||
return localPoint.LengthSquared() < radius * radius;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class DiscardSpline:Discarder
|
||||
{
|
||||
[Export]
|
||||
public Spline spline;
|
||||
|
||||
[Export]
|
||||
public float size;
|
||||
|
||||
[Export]
|
||||
public bool xzOnly = false;
|
||||
|
||||
[Export]
|
||||
public bool asFilledXZPath = false;
|
||||
|
||||
public override bool IsInside( Vector3 position )
|
||||
{
|
||||
if ( asFilledXZPath )
|
||||
{
|
||||
var bounds = spline.GetBounds().AsXZBox2();
|
||||
bounds.GrowRelativeToSize( 1/3f );
|
||||
|
||||
var p2 = Math2D.XZ( position );
|
||||
|
||||
if ( bounds.ContainsPoint( p2 ) )
|
||||
{
|
||||
//var path = spline.GetXZPath2();
|
||||
var cg = spline.GetConvex2Group();
|
||||
var insideGroup = cg.ContainsPoint( p2 );
|
||||
// var insidePath = insideGroup || path.PointInPath( p2, fastButUnreliableFilledXZPathChecks, false );
|
||||
|
||||
if ( insideGroup )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( size <= 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var curve = xzOnly ? spline.GetCurveXZ() : spline.GetCurve();
|
||||
|
||||
var testPosition = position;
|
||||
|
||||
if ( xzOnly )
|
||||
{
|
||||
testPosition.Y = 0;
|
||||
}
|
||||
|
||||
var distance = curve.GetDistanceTo( testPosition );
|
||||
|
||||
return distance < size;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
public partial class Discarder:Scatterer
|
||||
{
|
||||
[Export]
|
||||
public DiscardMode mode;
|
||||
|
||||
[Export]
|
||||
public DiscardBooleanCombinator combinator;
|
||||
|
||||
[Export]
|
||||
public BooleanLogicBinaryOperator discordOperator;
|
||||
|
||||
|
||||
public virtual bool IsInside( Vector3 position )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
points.ForEach( p =>
|
||||
{
|
||||
var inside = IsInside( p.globalPosition );
|
||||
var outside = ! inside;
|
||||
|
||||
var visible = DiscardMode.DiscardInside == mode && outside ||
|
||||
DiscardMode.DiscardOutside == mode && inside;
|
||||
|
||||
|
||||
if ( DiscardBooleanCombinator.Overwrite == combinator )
|
||||
{
|
||||
p.visible = visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = BooleanLogic.Binary( discordOperator, p.visible, visible );
|
||||
p.visible = result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum DiscardListMode
|
||||
{
|
||||
At_Least_Inside_One,
|
||||
Only_Inside_One,
|
||||
Must_Be_Inside_All
|
||||
}
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class DiscarderList:Discarder
|
||||
{
|
||||
[Export]
|
||||
public DiscardListMode listMode;
|
||||
|
||||
[Export]
|
||||
public bool childrenNeedToBeVisible = true;
|
||||
[Export]
|
||||
public bool childrenNeedToBeProcessing = false;
|
||||
|
||||
public override bool IsInside( Vector3 position )
|
||||
{
|
||||
var inside = 0;
|
||||
|
||||
var numNodes = 0;
|
||||
|
||||
Nodes.ForEachDirectChild<Discarder>( this,
|
||||
d =>
|
||||
{
|
||||
if ( ! IsChildEnabled( d, childrenNeedToBeVisible, childrenNeedToBeProcessing ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( d.IsInside( position ) )
|
||||
{
|
||||
inside ++;
|
||||
}
|
||||
|
||||
numNodes++;
|
||||
}
|
||||
);
|
||||
|
||||
if ( DiscardListMode.At_Least_Inside_One == listMode )
|
||||
{
|
||||
return inside > 0;
|
||||
}
|
||||
else if ( DiscardListMode.Only_Inside_One == listMode )
|
||||
{
|
||||
return inside == 1;
|
||||
}
|
||||
else if ( DiscardListMode.Must_Be_Inside_All == listMode )
|
||||
{
|
||||
return numNodes == inside;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class GenerateFence:GeneratorScatterer
|
||||
{
|
||||
[Export]
|
||||
public Spline spline;
|
||||
|
||||
[Export]
|
||||
public bool xzOnly = true;
|
||||
|
||||
[Export]
|
||||
public float sampleDensity = 1;
|
||||
|
||||
[Export]
|
||||
public GeneratorEntry segment;
|
||||
[Export]
|
||||
public float segmentLength;
|
||||
|
||||
[Export]
|
||||
public GeneratorEntry pole;
|
||||
[Export]
|
||||
public float poleLength;
|
||||
|
||||
[Export]
|
||||
public GeneratorEntry startPole;
|
||||
[Export]
|
||||
public float startPoleLength;
|
||||
|
||||
[Export]
|
||||
public GeneratorEntry endPole;
|
||||
[Export]
|
||||
public float endPoleLength;
|
||||
|
||||
SplineCurve last;
|
||||
LerpCurve3 equalSpacedCurve;
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
CreateWeights();
|
||||
var curve = spline.GetCurve();
|
||||
|
||||
if ( last != curve )
|
||||
{
|
||||
last = curve;
|
||||
equalSpacedCurve = LerpCurve3.SampledEqually( curve, sampleDensity );
|
||||
}
|
||||
|
||||
var curveLength = equalSpacedCurve.ComputeLength( 0 );
|
||||
var numPoints = Mathf.CeilToInt( curveLength * sampleDensity );
|
||||
|
||||
|
||||
var id = 0;
|
||||
|
||||
for ( int i = 0; i < numPoints; i++ )
|
||||
{
|
||||
var t = i / (float) ( numPoints - 1 );
|
||||
|
||||
var position = equalSpacedCurve.SampleAt( t );
|
||||
var rawDirection = equalSpacedCurve.GradientAt( t, 1f / 100f );
|
||||
var direction = rawDirection;
|
||||
var length = direction.Length();
|
||||
|
||||
|
||||
if ( length != 0 )
|
||||
{
|
||||
direction /= length;
|
||||
}
|
||||
|
||||
/*RJLog.Log( "i:", i, "t:", t,
|
||||
"P:", position,
|
||||
"L:", length,
|
||||
"RD:", rawDirection,
|
||||
"D:", direction
|
||||
);*/
|
||||
|
||||
var point = CreatePoint( points, id, position.X, position.Y, position.Z );
|
||||
|
||||
point.rotation = Math3D.LookRotation( direction, Vector3.Up );
|
||||
id = point.creatorID + 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
ScatterPoint CreatePoint( List<ScatterPoint> points, int id, float x, float y, float z )
|
||||
{
|
||||
var p = new ScatterPoint( this, id );
|
||||
|
||||
p.position = new Vector3( x, y, z );
|
||||
p.visible = ! setDiscarded;
|
||||
p.seed = Noise.CreateSeed( p.position );
|
||||
|
||||
AssginSceneAndContainer( p );
|
||||
|
||||
points.Add( p );
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class GenerateInBox:GeneratorScatterer
|
||||
{
|
||||
[Export]
|
||||
public Node3D cornerA;
|
||||
[Export]
|
||||
public Node3D cornerB;
|
||||
|
||||
[Export]
|
||||
public bool xzOnly = true;
|
||||
[Export]
|
||||
public float density = 10;
|
||||
|
||||
[Export]
|
||||
public bool snapToWorldGrid = false;
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
CreateWeights();
|
||||
|
||||
var minPosition = Math3D.MinPosition( cornerA, cornerB );
|
||||
var maxPosition = Math3D.MaxPosition( cornerA, cornerB );
|
||||
|
||||
if ( snapToWorldGrid )
|
||||
{
|
||||
var snapping = Vector3.One / density;
|
||||
minPosition = Math3D.SnapCeiled( minPosition, snapping );
|
||||
maxPosition = Math3D.SnapFloored( maxPosition, snapping );
|
||||
}
|
||||
|
||||
var pointsX = Mathf.CeilToInt( ( maxPosition.X - minPosition.X ) * density );
|
||||
var pointsY = Mathf.CeilToInt( ( maxPosition.Y - minPosition.Y ) * density );
|
||||
var pointsZ = Mathf.CeilToInt( ( maxPosition.Z - minPosition.Z ) * density );
|
||||
|
||||
var id = 0;
|
||||
|
||||
if ( xzOnly )
|
||||
{
|
||||
var y = ( cornerA.GlobalPosition.Y + cornerB.GlobalPosition.Y ) / 2f;
|
||||
|
||||
for ( int x = 0; x < pointsX; x++ )
|
||||
{
|
||||
var xPosition = MathX.Map( x, 0, pointsX - 1, minPosition.X, maxPosition.X );
|
||||
|
||||
for ( int z = 0; z < pointsZ; z++ )
|
||||
{
|
||||
var zPosition = MathX.Map( z, 0, pointsZ- 1, minPosition.Z, maxPosition.Z );
|
||||
|
||||
id = CreatePoint( points, id, xPosition, y, zPosition );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for ( int x = 0; x < pointsX; x++ )
|
||||
{
|
||||
var xPosition = MathX.Map( x, 0, pointsX - 1, minPosition.X, maxPosition.X );
|
||||
|
||||
for ( int y = 0; y < pointsY; y++ )
|
||||
{
|
||||
var yPosition = MathX.Map( y, 0, pointsY- 1, minPosition.Y, maxPosition.Y );
|
||||
|
||||
for ( int z = 0; z < pointsZ; z++ )
|
||||
{
|
||||
var zPosition = MathX.Map( z, 0, pointsZ- 1, minPosition.Z, maxPosition.Z );
|
||||
|
||||
id = CreatePoint( points, id, xPosition, yPosition, zPosition );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
int CreatePoint( List<ScatterPoint> points, int id, float x, float y, float z )
|
||||
{
|
||||
var p = new ScatterPoint( this, id++ );
|
||||
|
||||
p.position = new Vector3( x, y, z );
|
||||
p.visible = ! setDiscarded;
|
||||
p.seed = Noise.CreateSeed( p.position );
|
||||
|
||||
AssginSceneAndContainer( p );
|
||||
|
||||
points.Add( p );
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class GenerateOnSpline:GeneratorScatterer
|
||||
{
|
||||
[Export]
|
||||
public Spline spline;
|
||||
|
||||
[Export]
|
||||
public bool xzOnly = true;
|
||||
|
||||
[Export]
|
||||
public float density = 1;
|
||||
|
||||
SplineCurve last;
|
||||
LerpCurve3 equalSpacedCurve;
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
CreateWeights();
|
||||
var curve = spline.GetCurve();
|
||||
|
||||
if ( last != curve )
|
||||
{
|
||||
last = curve;
|
||||
equalSpacedCurve = LerpCurve3.SampledEqually( curve, density );
|
||||
}
|
||||
|
||||
var curveLength = equalSpacedCurve.ComputeLength( 0 );
|
||||
var numPoints = Mathf.CeilToInt( curveLength * density );
|
||||
|
||||
|
||||
var id = 0;
|
||||
|
||||
for ( int i = 0; i < numPoints; i++ )
|
||||
{
|
||||
var t = i / (float) ( numPoints - 1 );
|
||||
|
||||
var position = equalSpacedCurve.SampleAt( t );
|
||||
var rawDirection = equalSpacedCurve.GradientAt( t, 1f / 100f );
|
||||
var direction = rawDirection;
|
||||
var length = direction.Length();
|
||||
|
||||
|
||||
if ( length != 0 )
|
||||
{
|
||||
direction /= length;
|
||||
}
|
||||
|
||||
/*RJLog.Log( "i:", i, "t:", t,
|
||||
"P:", position,
|
||||
"L:", length,
|
||||
"RD:", rawDirection,
|
||||
"D:", direction
|
||||
);*/
|
||||
|
||||
var point = CreatePoint( points, id, position.X, position.Y, position.Z );
|
||||
|
||||
point.rotation = Math3D.LookRotation( direction, Vector3.Up );
|
||||
id = point.creatorID + 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
ScatterPoint CreatePoint( List<ScatterPoint> points, int id, float x, float y, float z )
|
||||
{
|
||||
var p = new ScatterPoint( this, id );
|
||||
|
||||
p.position = new Vector3( x, y, z );
|
||||
p.visible = ! setDiscarded;
|
||||
p.seed = Noise.CreateSeed( p.position );
|
||||
|
||||
AssginSceneAndContainer( p );
|
||||
|
||||
points.Add( p );
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class GeneratePinBoundary:GeneratorScatterer
|
||||
{
|
||||
[Export]
|
||||
public Spline spline;
|
||||
|
||||
[Export]
|
||||
public bool xzOnly = true;
|
||||
|
||||
[Export]
|
||||
public float sampleDensity;
|
||||
|
||||
|
||||
SplineCurve last;
|
||||
LerpCurve3 equalSpacedCurve;
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
var curve = spline.GetCurve();
|
||||
|
||||
if ( last != curve )
|
||||
{
|
||||
last = curve;
|
||||
equalSpacedCurve = LerpCurve3.SampledEqually( curve, sampleDensity );
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
int CreatePoint( List<ScatterPoint> points, int id, float x, float y, float z )
|
||||
{
|
||||
var p = new ScatterPoint( this, id++ );
|
||||
|
||||
p.position = new Vector3( x, y, z );
|
||||
p.visible = ! setDiscarded;
|
||||
p.seed = Noise.CreateSeed( p.position );
|
||||
|
||||
AssginSceneAndContainer( p );
|
||||
|
||||
points.Add( p );
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class GeneratorEntry:Node3D
|
||||
{
|
||||
[Export]
|
||||
public PackedScene packedScene;
|
||||
|
||||
[Export]
|
||||
public float probability = 1;
|
||||
|
||||
[Export]
|
||||
public Node3D container;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class GeneratorScatterer:Scatterer
|
||||
{
|
||||
[Export]
|
||||
public bool setDiscarded = true;
|
||||
|
||||
[Export]
|
||||
public PackedScene packedScene;
|
||||
|
||||
[Export]
|
||||
public Node3D container;
|
||||
|
||||
[Export]
|
||||
public bool useGeneratorEntryFromChildren = true;
|
||||
|
||||
[Export]
|
||||
public float childGeneratorNoiseScale = 1;
|
||||
|
||||
[Export]
|
||||
public Vector3 childGeneratorNoiseOffset = Vector3.Zero;
|
||||
|
||||
protected List<GeneratorEntry> childGenerators = new List<GeneratorEntry>();
|
||||
protected List<float> childGeneratorWeights = new List<float>();
|
||||
|
||||
public void CreateWeights()
|
||||
{
|
||||
if ( ! useGeneratorEntryFromChildren )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
childGenerators = Nodes.GetDirectChildren<GeneratorEntry>( this );
|
||||
childGeneratorWeights = Lists.Map( childGenerators, c => c.probability );
|
||||
|
||||
var sum = 0f;
|
||||
childGeneratorWeights.ForEach( w => sum += w );
|
||||
childGeneratorWeights = Lists.Map( childGeneratorWeights, c => c /= sum );
|
||||
}
|
||||
|
||||
public void AssginSceneAndContainer( ScatterPoint p )
|
||||
{
|
||||
if ( ! useGeneratorEntryFromChildren )
|
||||
{
|
||||
p.scene = packedScene;
|
||||
p.parent = container;
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = Noise.Perlin( ( p.position + childGeneratorNoiseOffset ) * childGeneratorNoiseScale );
|
||||
var index = _FindElementIndexWithWeights( childGeneratorWeights, value );
|
||||
var gs = childGenerators[ index ];
|
||||
|
||||
p.scene = gs.packedScene != null ? gs.packedScene : packedScene;
|
||||
p.parent = gs.container != null ? gs.container : container;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ScatterList:Scatterer
|
||||
{
|
||||
[Export]
|
||||
public bool childrenNeedToBeVisible = true;
|
||||
[Export]
|
||||
public bool childrenNeedToBeProcessing = false;
|
||||
|
||||
[Export]
|
||||
public bool clearChildContainers = false;
|
||||
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
if ( clearContainers )
|
||||
{
|
||||
clearContainers = false;
|
||||
ClearContainers();
|
||||
}
|
||||
|
||||
if ( clearChildContainers )
|
||||
{
|
||||
clearChildContainers = false;
|
||||
Nodes.ForEachDirectChild<Scatterer>( this, s => s.ClearContainers() );
|
||||
}
|
||||
|
||||
if ( ! ( update || updateAlways ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
update = false;
|
||||
|
||||
ScatterAndInstantiatePoints();
|
||||
}
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
var output = points;
|
||||
|
||||
Nodes.ForEachDirectChild<Scatterer>( this,
|
||||
( s )=>
|
||||
{
|
||||
if ( ! IsChildEnabled( s ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
output = s.Scatter( output );
|
||||
}
|
||||
);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
bool IsChildEnabled( Scatterer s )
|
||||
{
|
||||
return IsChildEnabled( s, childrenNeedToBeVisible, childrenNeedToBeProcessing );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class ScatterPoint
|
||||
{
|
||||
|
||||
protected Scatterer _creator;
|
||||
public Scatterer creator => _creator;
|
||||
protected int _creatorID;
|
||||
public int creatorID => _creatorID;
|
||||
|
||||
public ScatterPoint( Scatterer creator, int id )
|
||||
{
|
||||
this._creator = creator;
|
||||
this._creatorID = id;
|
||||
}
|
||||
|
||||
|
||||
public bool visible = false;
|
||||
public Vector3 position = Vector3.Zero;
|
||||
public bool useGlobalPosition = true;
|
||||
public Quaternion rotation = Quaternion.Identity;
|
||||
public bool useGlobalRotation = true;
|
||||
public Vector3 scale = Vector3.One;
|
||||
public PackedScene scene;
|
||||
public Node3D parent;
|
||||
public int seed;
|
||||
|
||||
public Vector3 globalPosition => useGlobalPosition || parent == null ?
|
||||
position : parent.ToGlobal( position );
|
||||
|
||||
|
||||
public bool CanBeReusedBy( ScatterPoint other )
|
||||
{
|
||||
return parent == other.parent && scene == other.scene;
|
||||
}
|
||||
|
||||
public void UpdateInstantiated( Node3D node )
|
||||
{
|
||||
ApplyTransform( node );
|
||||
}
|
||||
|
||||
|
||||
public Node3D Instantiate()
|
||||
{
|
||||
if ( ! visible || scene == null || parent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var node3D = scene.Instantiate<Node3D>();
|
||||
|
||||
parent.AddChild( node3D );
|
||||
node3D.Owner = parent.Owner;
|
||||
|
||||
ApplyTransform( node3D );
|
||||
|
||||
return node3D;
|
||||
}
|
||||
|
||||
void ApplyTransform( Node3D node3D )
|
||||
{
|
||||
if ( useGlobalPosition )
|
||||
{
|
||||
node3D.GlobalPosition = position;
|
||||
}
|
||||
else
|
||||
{
|
||||
node3D.Position = position;
|
||||
}
|
||||
|
||||
if ( useGlobalRotation )
|
||||
{
|
||||
Math3D.SetGlobalRotationTo( node3D, rotation );
|
||||
}
|
||||
else
|
||||
{
|
||||
node3D.Quaternion = rotation;
|
||||
}
|
||||
|
||||
node3D.Scale = scale;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass, Icon("res://Scripts/Rokojori/Rokojori-Action-Library/Icons/Scatterer.svg") ]
|
||||
public partial class Scatterer:Node3D
|
||||
{
|
||||
[Export]
|
||||
public bool update = false;
|
||||
[Export]
|
||||
public bool updateAlways = false;
|
||||
[Export]
|
||||
public Node3D[] containersToClearNodes;
|
||||
[Export]
|
||||
public bool clearContainers = false;
|
||||
|
||||
[Export]
|
||||
public bool removeDiscarded = false;
|
||||
|
||||
[Export]
|
||||
public int READ_ONLY_createdPoints = 0;
|
||||
[Export]
|
||||
public int READ_ONLY_instantiatedPoints = 0;
|
||||
[Export]
|
||||
public int READ_ONLY_reusedPoints = 0;
|
||||
[Export]
|
||||
public int READ_ONLY_remappedPoints = 0;
|
||||
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
if ( clearContainers )
|
||||
{
|
||||
clearContainers = false;
|
||||
ClearContainers();
|
||||
}
|
||||
|
||||
if ( ! ( update || updateAlways ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
update = false;
|
||||
|
||||
ScatterAndInstantiatePoints();
|
||||
}
|
||||
|
||||
public void ClearContainers()
|
||||
{
|
||||
Arrays.ForEach( containersToClearNodes,
|
||||
c =>
|
||||
{
|
||||
Nodes.RemoveAndDeleteChildren( c );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
class InstantiatedScatterPoint
|
||||
{
|
||||
public string hash;
|
||||
public ScatterPoint scatterPoint;
|
||||
public Node3D output;
|
||||
}
|
||||
|
||||
Dictionary<string,InstantiatedScatterPoint> _instantiatedPoints = new Dictionary<string, InstantiatedScatterPoint>();
|
||||
|
||||
Dictionary<Scatterer,int> _scattererIDs = new Dictionary<Scatterer, int>();
|
||||
|
||||
int GetScattererID( Scatterer s )
|
||||
{
|
||||
if ( ! _scattererIDs.ContainsKey( s ) )
|
||||
{
|
||||
_scattererIDs[ s ] = _scattererIDs.Count;
|
||||
}
|
||||
|
||||
return _scattererIDs[ s ];
|
||||
}
|
||||
|
||||
string GetScatterPointHash( ScatterPoint p )
|
||||
{
|
||||
var scatterID = GetScattererID( p.creator ) + ":" + p.creatorID;
|
||||
|
||||
return scatterID;
|
||||
}
|
||||
|
||||
public void ScatterAndInstantiatePoints()
|
||||
{
|
||||
if ( _instantiatedPoints.Count == 0 )
|
||||
{
|
||||
ClearContainers();
|
||||
}
|
||||
|
||||
var points = Scatter( new List<ScatterPoint>() );
|
||||
|
||||
READ_ONLY_createdPoints = points.Count;
|
||||
READ_ONLY_instantiatedPoints = 0;
|
||||
READ_ONLY_reusedPoints = 0;
|
||||
READ_ONLY_remappedPoints = 0;
|
||||
|
||||
var usedPoints = new HashSet<string>();
|
||||
|
||||
points.RemoveAll( p => ! p.visible );
|
||||
|
||||
points.ForEach( p =>
|
||||
{
|
||||
var hash = GetScatterPointHash( p );
|
||||
|
||||
if ( ! CanReuse( hash, p ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var existing = _instantiatedPoints[ hash ];
|
||||
existing.scatterPoint = p;
|
||||
existing.scatterPoint.UpdateInstantiated( existing.output );
|
||||
|
||||
usedPoints.Add( hash );
|
||||
|
||||
READ_ONLY_reusedPoints ++;
|
||||
return;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
var unused = new DictionaryList<PackedScene,InstantiatedScatterPoint>();
|
||||
|
||||
foreach ( var vk in _instantiatedPoints )
|
||||
{
|
||||
var ip = vk.Value;
|
||||
|
||||
if ( usedPoints.Contains( ip.hash ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
unused.Add( ip.scatterPoint.scene, ip );
|
||||
}
|
||||
|
||||
points.ForEach( p =>
|
||||
{
|
||||
var hash = GetScatterPointHash( p );
|
||||
|
||||
if ( usedPoints.Contains( hash ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( unused.ContainsKey( p.scene ) )
|
||||
{
|
||||
var unusedPoint = unused[ p.scene ].Find( ip => ip.scatterPoint.CanBeReusedBy( p ) );
|
||||
|
||||
if ( unusedPoint != null )
|
||||
{
|
||||
unused.Remove( p.scene, unusedPoint );
|
||||
unusedPoint.scatterPoint = p;
|
||||
unusedPoint.scatterPoint.UpdateInstantiated( unusedPoint.output );
|
||||
|
||||
usedPoints.Add( hash );
|
||||
|
||||
READ_ONLY_remappedPoints ++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var instantiatedOutput = p.Instantiate();
|
||||
|
||||
if ( instantiatedOutput == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ip = new InstantiatedScatterPoint();
|
||||
ip.hash = hash;
|
||||
ip.output = instantiatedOutput;
|
||||
ip.scatterPoint = p;
|
||||
|
||||
if ( _instantiatedPoints.ContainsKey( hash ) )
|
||||
{
|
||||
Nodes.RemoveAndDelete( _instantiatedPoints[ hash ].output );
|
||||
}
|
||||
|
||||
_instantiatedPoints[ hash ] = ip;
|
||||
usedPoints.Add( hash );
|
||||
|
||||
READ_ONLY_instantiatedPoints++;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Dictionaries.RemoveAll(
|
||||
_instantiatedPoints, ( k, v ) =>
|
||||
{
|
||||
if ( usedPoints.Contains( k ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Nodes.RemoveAndDelete( v.output );
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
bool CanReuse( string hash, ScatterPoint sp )
|
||||
{
|
||||
if ( ! _instantiatedPoints.ContainsKey( hash ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var existing = _instantiatedPoints[ hash ];
|
||||
|
||||
var canBeReused = existing.scatterPoint.CanBeReusedBy( sp );
|
||||
|
||||
return canBeReused;
|
||||
}
|
||||
|
||||
public List<ScatterPoint> Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
var returnedPoints = _Scatter( points );
|
||||
|
||||
if ( removeDiscarded )
|
||||
{
|
||||
returnedPoints.RemoveAll( p => ! p.visible );
|
||||
}
|
||||
|
||||
return returnedPoints;
|
||||
}
|
||||
|
||||
protected bool IsChildEnabled( Scatterer s, bool childrenNeedToBeVisible, bool childrenNeedToBeProcessing )
|
||||
{
|
||||
var enabled = true;
|
||||
|
||||
if ( childrenNeedToBeVisible )
|
||||
{
|
||||
enabled = enabled && s.Visible;
|
||||
}
|
||||
|
||||
if ( childrenNeedToBeProcessing )
|
||||
{
|
||||
enabled = enabled && ( s.ProcessMode != ProcessModeEnum.Disabled );
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
protected virtual List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum ScattererOwnPositionMode
|
||||
{
|
||||
Ignore,
|
||||
Add_Global,
|
||||
Add_Local
|
||||
}
|
||||
|
||||
public class ScattererOwnPosition
|
||||
{
|
||||
public static Vector3 ComputeOffset( ScattererOwnPositionMode mode, Node3D n )
|
||||
{
|
||||
var offset = Vector3.Zero;
|
||||
|
||||
if ( ScattererOwnPositionMode.Add_Global == mode )
|
||||
{
|
||||
offset += n.GlobalPosition;
|
||||
}
|
||||
|
||||
if ( ScattererOwnPositionMode.Add_Local == mode )
|
||||
{
|
||||
offset += n.Position;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ProjectOnColliders:Scatterer
|
||||
{
|
||||
|
||||
|
||||
|
||||
[ExportGroup("Ray")]
|
||||
[Export]
|
||||
public Vector3 rayDirection = Vector3.Down;
|
||||
|
||||
[Export]
|
||||
public float rayLength = 10;
|
||||
|
||||
[Export]
|
||||
public Vector3 rayOffset = Vector3.Zero;
|
||||
|
||||
[ExportGroup("Normal")]
|
||||
[Export(PropertyHint.Range, "0,1")]
|
||||
public float rotationAlignment = 1;
|
||||
|
||||
[Export]
|
||||
public bool discardSteepNormals = true;
|
||||
|
||||
[Export]
|
||||
public Vector3 steepNormalDirection = Vector3.Down;
|
||||
|
||||
[Export(PropertyHint.Range, "0,180")]
|
||||
public float steepNormalRemovalAngle = 0;
|
||||
|
||||
[ExportGroup("Collisions")]
|
||||
[Export( PropertyHint.Layers3DPhysics)]
|
||||
public uint collisionLayer = 0;
|
||||
|
||||
[Export]
|
||||
public bool collideWithAreas = true;
|
||||
|
||||
[Export]
|
||||
public bool collideWithBodies = true;
|
||||
|
||||
[Export]
|
||||
public bool hitFromInside = true;
|
||||
|
||||
[Export]
|
||||
public bool hitBackFaces = true;
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
var world = GetWorld3D();
|
||||
var ray = new PhysicsRayQueryParameters3D();
|
||||
var direction = rayDirection.Normalized();
|
||||
var normalizedSteepNormalDirection = steepNormalDirection.Normalized();
|
||||
|
||||
var steepNormalRemovalTreshold = Mathf.Cos( Mathf.DegToRad( steepNormalRemovalAngle ) );
|
||||
|
||||
points.ForEach(
|
||||
p =>
|
||||
{
|
||||
if ( ! p.visible )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ray.From = p.globalPosition;
|
||||
ray.To = ray.From + direction * rayLength;
|
||||
|
||||
var collisionData = CollisionData.FindCollision( world, ray,
|
||||
( cd ) =>
|
||||
{
|
||||
if ( ! CollisionData.HasCollisionLayer( cd.collider ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var colliderCollisionLayer = CollisionData.GetCollisionLayer( cd.collider );
|
||||
var collides = ( colliderCollisionLayer & collisionLayer ) != 0;
|
||||
// RJLog.Log( "Collision With:", "collides", collides, "colliderLayer:", colliderCollisionLayer, "own", collisionLayer, "name:", cd.collider.Name );
|
||||
return collides;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
p.visible = collisionData != null;
|
||||
|
||||
if ( ! p.visible )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( discardSteepNormals )
|
||||
{
|
||||
var dot = normalizedSteepNormalDirection.Dot( collisionData.normal );
|
||||
|
||||
if ( dot >= steepNormalRemovalTreshold )
|
||||
{
|
||||
p.visible = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
p.position = collisionData.position;
|
||||
var alginedRotation =Math3D.AlignUp( p.rotation, collisionData.normal );
|
||||
p.rotation = p.rotation.Slerp( alginedRotation, rotationAlignment );
|
||||
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class RandomizeTransform:Scatterer
|
||||
{
|
||||
[ExportGroup( "All" )]
|
||||
[Export]
|
||||
public float noiseScale = 1;
|
||||
[Export]
|
||||
public ScattererOwnPositionMode ownPositionMode = ScattererOwnPositionMode.Ignore;
|
||||
|
||||
[ExportGroup( "Position" )]
|
||||
[Export]
|
||||
public Vector3 positionOffset = Vector3.Zero;
|
||||
[Export]
|
||||
public float positionOffsetScale = 1;
|
||||
[Export]
|
||||
public float positionNoiseScale = 1;
|
||||
[Export]
|
||||
public Vector3 positionNoiseOffset = Vector3.Zero;
|
||||
|
||||
[ExportGroup( "Rotation" )]
|
||||
[Export]
|
||||
public Vector3 rotationOffset = Vector3.Zero;
|
||||
[Export]
|
||||
public float rotationOffsetScale = 1;
|
||||
[Export]
|
||||
public float rotationNoiseScale = 1;
|
||||
[Export]
|
||||
public Vector3 rotationNoiseOffset = Vector3.Zero;
|
||||
|
||||
[ExportGroup( "Scale" )]
|
||||
|
||||
[Export]
|
||||
public float uniformScaleMultiplyMin = 1;
|
||||
[Export]
|
||||
public float uniformScaleMultiplyMax = 1;
|
||||
|
||||
|
||||
[Export]
|
||||
public Vector3 componentScaleMinMultiply = Vector3.One;
|
||||
[Export]
|
||||
public Vector3 componentScaleMaxMultiply = Vector3.One;
|
||||
[Export]
|
||||
public float scaleNoiseScale = 1;
|
||||
[Export]
|
||||
public Vector3 scaleNoiseOffset = Vector3.Zero;
|
||||
|
||||
|
||||
protected override List<ScatterPoint> _Scatter( List<ScatterPoint> points )
|
||||
{
|
||||
var output = points;
|
||||
var ownOffset = ScattererOwnPosition.ComputeOffset( ownPositionMode, this );
|
||||
|
||||
points.ForEach(
|
||||
p =>
|
||||
{
|
||||
|
||||
var point = p.position;
|
||||
|
||||
var positionPerlin = ( point + positionNoiseOffset + ownOffset ) * ( noiseScale * positionNoiseScale );
|
||||
var rotationPerlin = ( point + rotationNoiseOffset + ownOffset ) * ( noiseScale * rotationNoiseScale );
|
||||
var scalePerlin = ( point + scaleNoiseOffset + ownOffset ) * ( noiseScale * scaleNoiseScale );
|
||||
|
||||
var positionRandom = Noise.PerlinPolar3( positionPerlin );
|
||||
var rotationRandom = Noise.PerlinPolar3( rotationPerlin );
|
||||
var scaleRandom = Noise.Perlin3( scalePerlin );
|
||||
var uniformScaleRandom = Noise.Perlin( scalePerlin + new Vector3( 100002, -10002, 1000 ) );
|
||||
|
||||
p.position += positionOffset * positionRandom * positionOffsetScale;
|
||||
p.rotation *= Quaternion.FromEuler( rotationOffset * rotationRandom * rotationOffsetScale );
|
||||
p.scale *= Math3D.LerpComponents( componentScaleMinMultiply, componentScaleMaxMultiply, scaleRandom );
|
||||
p.scale *= Mathf.Lerp( uniformScaleMultiplyMin, uniformScaleMultiplyMax, uniformScaleRandom );
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class GodotRandom:RandomEngine
|
||||
{
|
||||
static GodotRandom _instance;
|
||||
|
||||
public static GodotRandom Get()
|
||||
{
|
||||
if ( _instance != null )
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
_instance = new GodotRandom();
|
||||
return _instance;
|
||||
}
|
||||
|
||||
RandomNumberGenerator rng;
|
||||
|
||||
public GodotRandom()
|
||||
{
|
||||
rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
}
|
||||
|
||||
public override float Next()
|
||||
{
|
||||
return rng.Randf();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
public class Noise
|
||||
{
|
||||
public static int CreateSeed( Vector3 p )
|
||||
{
|
||||
var x = p.X;
|
||||
var y = p.Y;
|
||||
var z = p.Z;
|
||||
|
||||
x += 20422.4225f;
|
||||
y += 12353.299336f;
|
||||
z += 2139.4f;
|
||||
|
||||
x += 3254f;
|
||||
x = x % 157.3245f;
|
||||
|
||||
y += 8994f;
|
||||
y = y % 17.33636634f;
|
||||
|
||||
z += 3.4f;
|
||||
z = z % 15.99925f;
|
||||
|
||||
|
||||
var seed = 35891.323903f + x * 1000 + y * 11000 + z*20935;
|
||||
seed = seed % 0.12492f;
|
||||
seed = Mathf.Cos( seed * 2.235f ) + Mathf.Sin( z * 2102491054 ) + Mathf.Cos( y*48924.9042f);
|
||||
|
||||
var intSeed = Mathf.RoundToInt( seed * 20898977 );
|
||||
intSeed = Mathf.RoundToInt( intSeed + x * 42.3f -z *235 );
|
||||
intSeed = intSeed << 2;
|
||||
seed += y % z;
|
||||
seed += intSeed;
|
||||
seed = seed % 0.0012f;
|
||||
seed += y * 100203.3f;
|
||||
seed -= z * 0122f;
|
||||
|
||||
seed += x * 13.35f;
|
||||
seed = seed % ( y *32535 + z + 0.1221f );
|
||||
seed -= x * 2f;
|
||||
seed = seed % (x * 0.02f );
|
||||
seed += 2005235;
|
||||
seed = seed % 1157.5f;
|
||||
|
||||
return Mathf.RoundToInt( seed * 10000 );
|
||||
}
|
||||
|
||||
|
||||
public static float Random( Vector2 v )
|
||||
{
|
||||
var d = Math2D.Dot( v, new Vector2( 12.9898f, 78.233f ) );
|
||||
return MathX.Fract( Mathf.Sin ( d ) * 43758.5453123f );
|
||||
}
|
||||
|
||||
public static float Random( Vector3 v )
|
||||
{
|
||||
var d = Math3D.Dot( v, new Vector3( 12.9898f, 78.233f, 23.7219f ) );
|
||||
return MathX.Fract( Mathf.Sin ( d ) * 43758.5453123f );
|
||||
}
|
||||
|
||||
public static float Perlin( Vector2 position )
|
||||
{
|
||||
var index = position.Floor();
|
||||
var lerp = Math2D.Fract( position );
|
||||
|
||||
var uv = Math2D.SmoothStep( Vector2.Zero, Vector2.One, lerp );
|
||||
|
||||
var a = Random( index );
|
||||
var b = Random( index + new Vector2( 1.0f, 0.0f ) );
|
||||
var c = Random( index + new Vector2( 0.0f, 1.0f ) );
|
||||
var d = Random( index + new Vector2( 1.0f, 1.0f ) );
|
||||
|
||||
return MathX.Sample( a, b, c, d, uv );
|
||||
}
|
||||
|
||||
public static float Perlin( Vector3 position )
|
||||
{
|
||||
var index = position.Floor();
|
||||
var lerp = Math3D.Fract( position );
|
||||
|
||||
var uvw = Math3D.SmoothStep( Vector3.Zero, Vector3.One, lerp );
|
||||
|
||||
var ba = Random( index );
|
||||
var bb = Random( index + new Vector3( 1.0f, 0.0f, 0.0f ) );
|
||||
var bc = Random( index + new Vector3( 0.0f, 1.0f, 0.0f ) );
|
||||
var bd = Random( index + new Vector3( 1.0f, 1.0f, 0.0f ) );
|
||||
|
||||
var ta = Random( index + new Vector3( 0.0f, 0.0f, 1.0f ) );
|
||||
var tb = Random( index + new Vector3( 1.0f, 0.0f, 1.0f ) );
|
||||
var tc = Random( index + new Vector3( 0.0f, 1.0f, 1.0f ) );
|
||||
var td = Random( index + new Vector3( 1.0f, 1.0f, 1.0f ) );
|
||||
|
||||
return MathX.Sample( ba, bb, bc, bd, ta, tb, tc, td, uvw );
|
||||
|
||||
}
|
||||
|
||||
public static float PerlinPolar( Vector3 position )
|
||||
{
|
||||
return Perlin( position ) * 2 - 1;
|
||||
}
|
||||
|
||||
static readonly Vector3 Perlin3OffsetY = new Vector3( 31789.23f, -2101.23f, 912990.21f );
|
||||
static readonly Vector3 Perlin3OffsetZ = new Vector3( 91290.0340f, 12921, -99122.21424f );
|
||||
|
||||
public static Vector3 Perlin3( Vector3 position, Vector3? offsetY =null, Vector3? offsetZ = null )
|
||||
{
|
||||
var offY = ( Vector3 ) ( offsetY == null ? Perlin3OffsetY : offsetY );
|
||||
var offZ = ( Vector3 ) ( offsetZ == null ? Perlin3OffsetZ : offsetZ );
|
||||
|
||||
var x = Perlin( position );
|
||||
var y = Perlin( position + offY );
|
||||
var z = Perlin( position + offZ );
|
||||
|
||||
return new Vector3( x, y, z );
|
||||
|
||||
}
|
||||
|
||||
public static Vector3 PerlinPolar3( Vector3 position, Vector3? offsetY =null, Vector3? offsetZ = null )
|
||||
{
|
||||
return Perlin3( position, offsetY, offsetZ ) * 2 - Vector3.One;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -290,6 +290,24 @@ namespace Rokojori
|
|||
return selection;
|
||||
}
|
||||
|
||||
public int IndexFromUnnormalizedWeights( List<float> weights, float sumWeights = 0 )
|
||||
{
|
||||
if ( sumWeights <= 0 )
|
||||
{
|
||||
sumWeights = 0;
|
||||
weights.ForEach( w => sumWeights += w );
|
||||
}
|
||||
|
||||
return _FindElementIndexWithWeights( weights, Next() * sumWeights );
|
||||
}
|
||||
|
||||
|
||||
public int IndexFromNormalizedWeights( List<float> weights, float sumWeights = 0 )
|
||||
{
|
||||
|
||||
return IndexFromUnnormalizedWeights( weights, 1 );
|
||||
}
|
||||
|
||||
int _FindElementIndexWithWeights( List<float> weights, float value )
|
||||
{
|
||||
var limit = 0f;
|
||||
|
|
|
@ -139,3 +139,25 @@ vec4 fade( vec4 rgba, float fade )
|
|||
{
|
||||
return vec4( rgba.rgb, rgba.a * fade );
|
||||
}
|
||||
|
||||
vec4 straightToPremultipliedColor( vec4 color )
|
||||
{
|
||||
return vec4( color.rgb * color.a, color.a );
|
||||
}
|
||||
|
||||
vec4 premultipliedToStraightColor( vec4 color )
|
||||
{
|
||||
color.a = max( color.a, 0.000001f );
|
||||
|
||||
return vec4( color.rgb / color.a, color.a );
|
||||
}
|
||||
|
||||
|
||||
vec4 blendMode_alpha( vec4 top, vec4 bottom )
|
||||
{
|
||||
float alpha = top.a + bottom.a * ( 1.0 - top.a );
|
||||
vec3 color = top.rgb * top.a + bottom.rgb * bottom.a * ( 1.0 - top.a );
|
||||
|
||||
return vec4( color, alpha );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
float random( vec2 uv )
|
||||
{
|
||||
return fract( sin( dot( uv.xy, vec2( 12.9898, 78.233 ) ) ) * 43758.5453123 );
|
||||
}
|
||||
|
||||
|
||||
float worley( vec2 uv, float columns, float rows )
|
||||
{
|
||||
|
||||
vec2 index_uv = floor( vec2( uv.x * columns, uv.y * rows ) );
|
||||
vec2 fract_uv = fract( vec2( uv.x * columns, uv.y * rows ) );
|
||||
|
||||
float minimum_dist = 1.0;
|
||||
|
||||
for ( int y= -1; y <= 1; y++ )
|
||||
{
|
||||
for ( int x= -1; x <= 1; x++ )
|
||||
{
|
||||
vec2 neighbor = vec2( float( x ), float( y ) );
|
||||
vec2 point = random( index_uv + neighbor );
|
||||
|
||||
vec2 diff = neighbor + point - fract_uv;
|
||||
float dist = length (diff );
|
||||
|
||||
minimum_dist = min( minimum_dist, dist );
|
||||
}
|
||||
}
|
||||
|
||||
return minimum_dist;
|
||||
}
|
||||
|
||||
vec2 voronoi( vec2 uv, float columns, float rows )
|
||||
{
|
||||
vec2 index_uv = floor( vec2( uv.x * columns, uv.y * rows ) );
|
||||
vec2 fract_uv = fract( vec2( uv.x * columns, uv.y * rows ) );
|
||||
|
||||
float minimum_dist = 1.0;
|
||||
vec2 minimum_point;
|
||||
|
||||
for ( int y= -1; y <= 1; y++ )
|
||||
{
|
||||
for ( int x= -1; x <= 1; x++ )
|
||||
{
|
||||
vec2 neighbor = vec2( float( x ), float( y ) );
|
||||
vec2 point = random( index_uv + neighbor );
|
||||
|
||||
vec2 diff = neighbor + point - fract_uv;
|
||||
float dist = length( diff );
|
||||
|
||||
if ( dist < minimum_dist )
|
||||
{
|
||||
minimum_dist = dist;
|
||||
minimum_point = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return minimum_point;
|
||||
}
|
|
@ -8,3 +8,19 @@ vec3 worldToLocal( vec3 _VERTEX, mat4 _MODEL_MATRIX )
|
|||
{
|
||||
return ( inverse( _MODEL_MATRIX ) * vec4( _VERTEX, 1.0 ) ).xyz;
|
||||
}
|
||||
|
||||
vec2 tilingOffset( vec2 uv, vec4 tilingOffset )
|
||||
{
|
||||
uv *= tilingOffset.xy;
|
||||
uv += tilingOffset.zw;
|
||||
|
||||
return uv;
|
||||
}
|
||||
|
||||
vec2 tilingOffsetRepeat( vec2 uv, vec4 tilingOffset )
|
||||
{
|
||||
uv *= tilingOffset.xy;
|
||||
uv += tilingOffset.zw;
|
||||
|
||||
return mod( uv, vec2(1,1) );
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Godot;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ColorPropertyName : Resource
|
||||
{
|
||||
[Export]
|
||||
public string propertyName;
|
||||
|
||||
public void Set( Material material, Color value )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var shaderMaterial = ( ShaderMaterial ) material;
|
||||
shaderMaterial.SetShaderParameter( propertyName, value );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
propertyInfo.SetValue( material, value );
|
||||
|
||||
}
|
||||
|
||||
public Color Get( Material material )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var m = ( ShaderMaterial ) material;
|
||||
return (Color) m.GetShaderParameter( propertyName );
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return default( Color );
|
||||
}
|
||||
|
||||
return (Color) propertyInfo.GetValue( material );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Godot;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class FloatPropertyName : Resource
|
||||
{
|
||||
[Export]
|
||||
public string propertyName;
|
||||
|
||||
public void Set( Material material, float value )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var shaderMaterial = ( ShaderMaterial ) material;
|
||||
shaderMaterial.SetShaderParameter( propertyName, value );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
propertyInfo.SetValue( material, value );
|
||||
|
||||
}
|
||||
|
||||
public float Get( Material material )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var m = ( ShaderMaterial ) material;
|
||||
return (float) m.GetShaderParameter( propertyName );
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return default( float );
|
||||
}
|
||||
|
||||
return (float) propertyInfo.GetValue( material );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using Godot;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class Vector2PropertyName : Resource
|
||||
{
|
||||
[Export]
|
||||
public string propertyName;
|
||||
|
||||
public void Set( Material material, Vector2 value )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var shaderMaterial = ( ShaderMaterial ) material;
|
||||
shaderMaterial.SetShaderParameter( propertyName, value );
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
propertyInfo.SetValue( material, value );
|
||||
|
||||
}
|
||||
|
||||
public Vector2 Get( Material material )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var m = ( ShaderMaterial ) material;
|
||||
return (Vector2) m.GetShaderParameter( propertyName );
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return default( Vector2 );
|
||||
}
|
||||
|
||||
return (Vector2) propertyInfo.GetValue( material );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Godot;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class Vector3PropertyName : Resource
|
||||
{
|
||||
[Export]
|
||||
public string propertyName;
|
||||
|
||||
public void Set( Material material, Vector3 value )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var shaderMaterial = ( ShaderMaterial ) material;
|
||||
shaderMaterial.SetShaderParameter( propertyName, value );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
propertyInfo.SetValue( material, value );
|
||||
|
||||
}
|
||||
|
||||
public Vector3 Get( Material material )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var m = ( ShaderMaterial ) material;
|
||||
return (Vector3) m.GetShaderParameter( propertyName );
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return default( Vector3 );
|
||||
}
|
||||
|
||||
return (Vector3) propertyInfo.GetValue( material );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Godot;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class Vector4PropertyName : Resource
|
||||
{
|
||||
[Export]
|
||||
public string propertyName;
|
||||
|
||||
public void Set( Material material, Vector4 value )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var shaderMaterial = ( ShaderMaterial ) material;
|
||||
shaderMaterial.SetShaderParameter( propertyName, value );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
propertyInfo.SetValue( material, value );
|
||||
|
||||
}
|
||||
|
||||
public Vector4 Get( Material material )
|
||||
{
|
||||
if ( material is ShaderMaterial )
|
||||
{
|
||||
var m = ( ShaderMaterial ) material;
|
||||
return (Vector4) m.GetShaderParameter( propertyName );
|
||||
}
|
||||
|
||||
var propertyInfo = material.GetType().GetProperty( propertyName );
|
||||
|
||||
if ( propertyInfo == null )
|
||||
{
|
||||
return default( Vector4 );
|
||||
}
|
||||
|
||||
return (Vector4) propertyInfo.GetValue( material );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class DictionaryList<K,V>:Dictionary<K,List<V>>
|
||||
{
|
||||
public void Add( K key, V value )
|
||||
{
|
||||
if ( ! ContainsKey( key ) )
|
||||
{
|
||||
this[ key ] = new List<V>();
|
||||
}
|
||||
|
||||
this[ key ].Add( value );
|
||||
}
|
||||
|
||||
public void Remove( K key, V value )
|
||||
{
|
||||
if ( ! ContainsKey( key ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var list = this[ key ];
|
||||
|
||||
list.Remove( value );
|
||||
|
||||
if ( list.Count == 0 )
|
||||
{
|
||||
Remove( key );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class TimeLineManager:RJTimeLineManager
|
||||
{
|
||||
|
@ -51,6 +52,38 @@ namespace Rokojori
|
|||
return _idCounter;
|
||||
}
|
||||
|
||||
public static float GetPosition( RJTimeLine timeLine )
|
||||
{
|
||||
var manager = Unique<TimeLineManager>.Get();
|
||||
|
||||
if ( manager == null )
|
||||
{
|
||||
return Time.GetTicksMsec() / 1000f;
|
||||
}
|
||||
|
||||
var index = Arrays.IndexOf( manager.timeLines, timeLine );
|
||||
|
||||
index = Mathf.Max( index, 0 );
|
||||
|
||||
return (float) manager.GetPosition( index );
|
||||
}
|
||||
|
||||
|
||||
public static float GetPhase( RJTimeLine timeLine, float duration, float offset = 0 )
|
||||
{
|
||||
var time = GetPosition( timeLine ) + offset;
|
||||
|
||||
return ( time % duration ) / duration;
|
||||
}
|
||||
|
||||
public static float GetRangePhase( RJTimeLine timeLine, float start, float end )
|
||||
{
|
||||
var time = GetPosition( timeLine );
|
||||
var normalized = MathX.Normalize( time, start, end );
|
||||
return normalized;
|
||||
}
|
||||
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
_runners.ForEach( r => r.UpdateTimeLine( delta, this ) );
|
||||
|
|
|
@ -7,6 +7,24 @@ namespace Rokojori
|
|||
{
|
||||
public class Arrays
|
||||
{
|
||||
public static int IndexOf<T>( T[] values, T other )
|
||||
{
|
||||
return Array.IndexOf( values, other );
|
||||
}
|
||||
|
||||
public static int FindIndex<T>( T[] values, Func<T,bool> predicate )
|
||||
{
|
||||
for ( int i = 0; i < values.Length; i++ )
|
||||
{
|
||||
if ( predicate( values[ i ] ) )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static bool Contains <T>( T[] values, T other )
|
||||
{
|
||||
return Array.IndexOf( values, other ) != -1;
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum BooleanLogicBinaryOperator
|
||||
{
|
||||
AND,
|
||||
OR,
|
||||
XOR,
|
||||
NOR,
|
||||
NAND,
|
||||
XNOR
|
||||
}
|
||||
|
||||
public class BooleanLogic
|
||||
{
|
||||
public static bool Binary( BooleanLogicBinaryOperator op, bool l, bool r )
|
||||
{
|
||||
switch ( op )
|
||||
{
|
||||
case BooleanLogicBinaryOperator.AND: return l && r;
|
||||
case BooleanLogicBinaryOperator.OR: return l || r;
|
||||
case BooleanLogicBinaryOperator.XOR: return l || r && ! ( l && r );
|
||||
case BooleanLogicBinaryOperator.NOR: return ! ( l || r ) ;
|
||||
case BooleanLogicBinaryOperator.NAND: return ! ( l && r ) ;
|
||||
case BooleanLogicBinaryOperator.XNOR: return ( ! l && ! r ) || ( l && r ) ;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Dictionaries
|
||||
{
|
||||
public static void RemoveAll<K,V>( Dictionary<K,V> dictionary, Func<K,V,bool> predicate )
|
||||
{
|
||||
var list = new List<K>();
|
||||
|
||||
foreach ( var kv in dictionary )
|
||||
{
|
||||
if ( predicate( kv.Key, kv.Value ) )
|
||||
{
|
||||
list.Add( kv.Key );
|
||||
}
|
||||
}
|
||||
|
||||
list.ForEach( k => dictionary.Remove( k ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ namespace Rokojori
|
|||
|
||||
}
|
||||
|
||||
public static Type GetTypeByName( string name)
|
||||
public static Type GetTypeByName( string name )
|
||||
{
|
||||
var assemblies = new List<Assembly>();
|
||||
assemblies.AddRange( AppDomain.CurrentDomain.GetAssemblies() );
|
||||
|
@ -166,7 +166,7 @@ namespace Rokojori
|
|||
}
|
||||
}
|
||||
|
||||
public static System.Reflection.FieldInfo GetFieldInfo( object instance, string memberName )
|
||||
public static FieldInfo GetFieldInfo( object instance, string memberName )
|
||||
{
|
||||
var type = instance.GetType();
|
||||
var fields = type.GetFields();
|
||||
|
|
|
@ -30,13 +30,12 @@ namespace Rokojori
|
|||
{
|
||||
var container = (UIStylePropertyContainer) control;
|
||||
|
||||
var left = UIStyle.Left( container );
|
||||
var right = UIStyle.Right( container );
|
||||
var top = UIStyle.Top( container );
|
||||
var bottom = UIStyle.Bottom( container );
|
||||
|
||||
var offsetX = UINumber.Compute( control, left, 0 ) - UINumber.Compute( control, right, 0 );
|
||||
var offsetY = UINumber.Compute( control, top, 0 ) - UINumber.Compute( control, bottom, 0 );
|
||||
var offsetX = UINumber.Compute( control, UIStyleNumberProperty.Left, 0 ) -
|
||||
UINumber.Compute( control, UIStyleNumberProperty.Right, 0 );
|
||||
|
||||
var offsetY = UINumber.Compute( control, UIStyleNumberProperty.Top, 0 ) -
|
||||
UINumber.Compute( control, UIStyleNumberProperty.Bottom, 0 );
|
||||
|
||||
UILayouting.SetPosition( control, parentOffset + new Vector2( offset + offsetX, yOffset + offsetY ) );
|
||||
}
|
||||
|
@ -66,33 +65,66 @@ namespace Rokojori
|
|||
|
||||
var maxWidth = 0f;
|
||||
var maxHeight = 0f;
|
||||
var maxVerticalPlacementOffset = 0f;
|
||||
var maxLineY = lines.Count > 0 ? lines[ lines.Count - 1 ].maxY : 0;
|
||||
|
||||
if ( UINumber.IsNullOrNone( UIStyle.Width( region ) ) )
|
||||
region.contentSize.X = 0f;
|
||||
region.contentSize.Y = maxLineY;
|
||||
|
||||
lines.ForEach( l => { region.contentSize.X = Mathf.Max( region.contentSize.X, l.maxX ); } );
|
||||
|
||||
|
||||
if ( UINumber.IsNullOrNone( region, UIStyleNumberProperty.Width ) )
|
||||
{
|
||||
lines.ForEach( l => { maxWidth = Mathf.Max( maxWidth, l.maxX ); } );
|
||||
maxWidth = region.contentSize.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxWidth = UINumber.Compute( region, UIStyle.Width( region ) );
|
||||
maxWidth = UINumber.Compute( region, UIStyleNumberProperty.Width );
|
||||
}
|
||||
|
||||
if ( lines.Count > 0 )
|
||||
if ( ! UINumber.IsNullOrNone( UIStyle.GetUINumberProperty( region, UIStyleNumberProperty.Height ) ) )
|
||||
{
|
||||
maxHeight = lines[ lines.Count - 1 ].maxY;
|
||||
maxHeight = UINumber.Compute( region, UIStyleNumberProperty.Height );
|
||||
maxVerticalPlacementOffset = maxHeight - maxLineY;
|
||||
|
||||
}
|
||||
else if ( lines.Count > 0 )
|
||||
{
|
||||
maxHeight = maxLineY;
|
||||
}
|
||||
|
||||
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 margin = UINumber.Compute( region, UIStyleNumberProperty.Margin, 0 );
|
||||
var marginLeft = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginLeft, 0 );
|
||||
var marginTop = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginTop, 0 );
|
||||
|
||||
var marginRight = margin + UINumber.Compute( region, UIStyle.MarginRight( region ), 0 );
|
||||
var marginBottom = margin + UINumber.Compute( region, UIStyle.MarginBottom( region ), 0 );
|
||||
var marginRight = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginRight, 0 );
|
||||
var marginBottom = margin + UINumber.Compute( region, UIStyleNumberProperty.MarginBottom, 0 );
|
||||
|
||||
|
||||
var marginOffset = new Vector2( marginLeft, marginTop );
|
||||
var verticalPlacementOffset = UINumber.Compute( region, UIStyleNumberProperty.VerticalPlacement, 0, maxVerticalPlacementOffset );
|
||||
|
||||
// if ( region.Name == "Audio" )
|
||||
// {
|
||||
// RJLog.Log( "Audio Placements",
|
||||
// "maxHeight:", maxHeight,
|
||||
// "maxLineY:", maxLineY,
|
||||
// "maxVerticalPlacementOffset", maxVerticalPlacementOffset,
|
||||
// "verticalPlacementOffset", verticalPlacementOffset
|
||||
// );
|
||||
// }
|
||||
|
||||
|
||||
var marginOffset = new Vector2( marginLeft, marginTop + verticalPlacementOffset );
|
||||
|
||||
region.contentOffset = marginOffset;
|
||||
|
||||
PlaceControls( region, lines, marginOffset );
|
||||
|
||||
var alignmentWidth = maxWidth + marginLeft + marginRight;
|
||||
var horizontalAlignment = UINumber.Compute( region, UIStyleNumberProperty.HorizontalAlignment, 0 );
|
||||
region.contentOffset.X = Mathf.Lerp( 0, alignmentWidth - region.contentSize.X, horizontalAlignment / 100f );
|
||||
|
||||
var verticalMargins = marginTop + marginBottom;
|
||||
var horizontalMargins = marginLeft + marginRight;
|
||||
|
||||
|
@ -124,12 +156,13 @@ namespace Rokojori
|
|||
static List<Line> CreateLines( UIRegion region )
|
||||
{
|
||||
var x = 0f;
|
||||
var width = UINumber.Compute( region, UIStyle.Width( region ), 100000000f );
|
||||
var width = UINumber.Compute( region, UIStyleNumberProperty.Width, 100000000f );
|
||||
|
||||
var lines = new List<Line>();
|
||||
var currentLine = new Line();
|
||||
|
||||
var elementSpacing = UINumber.Compute( region, UIStyle.ElementSpacing( region ), 0f );
|
||||
var elementSpacing = UINumber.Compute( region, UIStyleNumberProperty.ElementSpacing, 0f );
|
||||
var lineSpacing = UINumber.Compute( region, UIStyleNumberProperty.LineSpacing, 0f );
|
||||
|
||||
Nodes.ForEachDirectChild<Control>( region, c => UILayouting.UpdateChild( c ) );
|
||||
|
||||
|
@ -137,6 +170,10 @@ namespace Rokojori
|
|||
Nodes.ForEachDirectChild<Control>( region,
|
||||
child =>
|
||||
{
|
||||
if ( ! child.Visible )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var styleContainer = child as UIStylePropertyContainer;
|
||||
|
||||
|
@ -150,12 +187,16 @@ namespace Rokojori
|
|||
|
||||
var nextEndX = x + cWidth + elementSpacing;
|
||||
|
||||
if ( nextEndX > width )
|
||||
var lineWrap = UIStyle.LineWrap( styleContainer );
|
||||
|
||||
lineWrap = lineWrap == UILineWrap.___ ? UILineWrap.Wrap_On_Overflow : lineWrap;
|
||||
|
||||
if ( UILineWrap.Wrap_Never != lineWrap && ( UILineWrap.Wrap_Always == lineWrap || nextEndX > width ) )
|
||||
{
|
||||
lines.Add( currentLine );
|
||||
currentLine = new Line();
|
||||
x = 0;
|
||||
currentLine.y = lines[ lines.Count - 1 ].maxY;
|
||||
currentLine.y = lines[ lines.Count - 1 ].maxY + lineSpacing;
|
||||
nextEndX = cWidth + elementSpacing;
|
||||
}
|
||||
|
||||
|
@ -175,7 +216,7 @@ namespace Rokojori
|
|||
|
||||
if ( lines.Count > 0 )
|
||||
{
|
||||
currentLine.y = lines[ lines.Count - 1 ].maxY;
|
||||
currentLine.y = lines[ lines.Count - 1 ].maxY + lineSpacing;
|
||||
}
|
||||
|
||||
lines.Add( currentLine );
|
||||
|
@ -188,17 +229,17 @@ namespace Rokojori
|
|||
|
||||
static void AdjustLines( UIRegion region, List<Line> lines )
|
||||
{
|
||||
var verticalAlignment = UINumber.Compute( region, region.verticalAlignment, 0.5f, 1 );
|
||||
var verticalAlignment = UINumber.Compute( region, UIStyleNumberProperty.VerticalAlignment, 0.5f, 1 );
|
||||
|
||||
lines.ForEach( line => AdjustVerticalAlignment( region, line, verticalAlignment ) );
|
||||
|
||||
if ( UINumber.IsNullOrNone( UIStyle.Width( region ) ) )
|
||||
if ( UINumber.IsNullOrNone( region, UIStyleNumberProperty.Width ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var horizontalAlignment = UINumber.Compute( region, region.horizontalAlignment, 0.5f, 1 );
|
||||
var maxWidth = UINumber.Compute( region, UIStyle.Width( region ), 0 );
|
||||
var horizontalAlignment = UINumber.Compute( region, UIStyleNumberProperty.HorizontalAlignment, 0.5f, 1 );
|
||||
var maxWidth = UINumber.Compute( region, UIStyleNumberProperty.Width, 0 );
|
||||
|
||||
lines.ForEach( line => AdjustHorizontalAlignment( region, line, horizontalAlignment, maxWidth ) );
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Rokojori
|
|||
{
|
||||
public enum UILayout
|
||||
{
|
||||
___,
|
||||
Flow_Left_Top
|
||||
}
|
||||
}
|
|
@ -6,43 +6,149 @@ namespace Rokojori
|
|||
{
|
||||
public class UILayouting
|
||||
{
|
||||
public static Vector2 GetContentSize( Control control )
|
||||
{
|
||||
if ( control is UIRegion )
|
||||
{
|
||||
return ( (UIRegion) control ).contentSize;
|
||||
}
|
||||
|
||||
return control.Size;
|
||||
}
|
||||
|
||||
public static Vector2 GetContentOffset( Control control )
|
||||
{
|
||||
if ( control is UIRegion )
|
||||
{
|
||||
return ( (UIRegion) control ).contentOffset;
|
||||
}
|
||||
|
||||
return control.Size;
|
||||
}
|
||||
|
||||
public static void UpdateChild( Control control )
|
||||
{
|
||||
if ( ! control.Visible )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( control is UIRegion )
|
||||
{
|
||||
var childUIRegion = (UIRegion) control;
|
||||
childUIRegion.Layout();
|
||||
}
|
||||
else if ( control is UIImage )
|
||||
else if ( control is UIImage || control is UIBorderImage )
|
||||
{
|
||||
var uiImage = (UIImage) control;
|
||||
var tw = 0;
|
||||
var th = 0;
|
||||
|
||||
if ( uiImage.Texture == null )
|
||||
if ( control is UIImage )
|
||||
{
|
||||
uiImage.Size = new Vector2( 0, 0 );
|
||||
return;
|
||||
var uiImage = (UIImage) control;
|
||||
|
||||
if ( uiImage.Texture == null )
|
||||
{
|
||||
uiImage.Size = new Vector2( 0, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
tw = uiImage.Texture.GetWidth();
|
||||
th = uiImage.Texture.GetHeight();
|
||||
}
|
||||
else if ( control is UIBorderImage )
|
||||
{
|
||||
var uiBorderImage = (UIBorderImage) control;
|
||||
|
||||
if ( uiBorderImage.Texture == null )
|
||||
{
|
||||
uiBorderImage.Size = new Vector2( 0, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
tw = uiBorderImage.Texture.GetWidth();
|
||||
th = uiBorderImage.Texture.GetHeight();
|
||||
}
|
||||
|
||||
var tw = uiImage.Texture.GetWidth();
|
||||
var th = uiImage.Texture.GetHeight();
|
||||
|
||||
var w = UINumber.Compute( control, uiImage.width, tw, tw / 100f );
|
||||
var h = UINumber.Compute( control, uiImage.height, th, th / 100f );
|
||||
var container = (UIStylePropertyContainer) control;
|
||||
|
||||
uiImage.Size = new Vector2( w, h );
|
||||
var w = UINumber.Compute( control, UIStyleNumberProperty.Width, tw, tw / 100f );
|
||||
var h = UINumber.Compute( control, UIStyleNumberProperty.Height, th, th / 100f );
|
||||
|
||||
control.Size = new Vector2( w, h );
|
||||
|
||||
if ( control is UIImage )
|
||||
{
|
||||
var uiImage = (UIImage) control;
|
||||
|
||||
if ( uiImage.Material != null )
|
||||
{
|
||||
var ui = Unique<UI>.Get();
|
||||
|
||||
if ( ui == null )
|
||||
{
|
||||
ui = NodesWalker.Get().GetInParents( control, n => n is UI ) as UI;
|
||||
}
|
||||
|
||||
if ( ui == null )
|
||||
{
|
||||
RJLog.Log( "No UI Found" );
|
||||
return;
|
||||
}
|
||||
|
||||
//RJLog.Log( "Setting Size", ui.settings.sizePropertyName.propertyName, HierarchyName.Of( uiImage ) );
|
||||
ui.settings.sizePropertyName.Set( uiImage.Material, uiImage.Size );
|
||||
|
||||
UIShaderProperties.UpdateProperties( uiImage, uiImage.Material );
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if ( control is UIText )
|
||||
{
|
||||
var text = (UIText) control;
|
||||
|
||||
var container = (UIStylePropertyContainer) control;
|
||||
|
||||
text.uiTextLabelSettings.FontSize =
|
||||
UINumber.ComputeInt( control, UIStyleNumberProperty.FontSize, UINumber.em(), UINumber.em() / 100f );
|
||||
text.uiTextLabelSettings.FontColor =
|
||||
UIColor.Compute( control, UIStyleColorProperty.FontColor, Colors.White );
|
||||
|
||||
text.uiTextLabelSettings.OutlineSize =
|
||||
UINumber.ComputeInt( control, UIStyleNumberProperty.FontOutlineSize, 0 );
|
||||
|
||||
text.uiTextLabelSettings.OutlineColor =
|
||||
UIColor.Compute( control, UIStyleColorProperty.FontOutlineColor, Colors.Transparent );
|
||||
|
||||
text.uiTextLabelSettings.ShadowSize =
|
||||
UINumber.ComputeInt( control, UIStyleNumberProperty.FontShadowSize, 0 );
|
||||
|
||||
text.uiTextLabelSettings.ShadowColor =
|
||||
UIColor.Compute( control, UIStyleColorProperty.FontShadowColor, Colors.Black );
|
||||
|
||||
text.uiTextLabelSettings.ShadowOffset = new Vector2(
|
||||
UINumber.Compute( control, UIStyleNumberProperty.FontShadowOffsetX, 0 ),
|
||||
UINumber.Compute( control, UIStyleNumberProperty.FontShadowOffsetY, 0 )
|
||||
);
|
||||
|
||||
control.UpdateMinimumSize();
|
||||
control.Size = control.GetMinimumSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
control.UpdateMinimumSize();
|
||||
control.Size = control.GetMinimumSize();
|
||||
// control.UpdateMinimumSize();
|
||||
// control.Size = control.GetMinimumSize();
|
||||
}
|
||||
|
||||
UILayouting.UpdatePivot( control );
|
||||
}
|
||||
|
||||
public static void SetPositionInParentAnchor( UIStylePropertyContainer region )
|
||||
public static void SetPositionInParentAnchor( UIStylePropertyContainer container )
|
||||
{
|
||||
var control = (Control) region;
|
||||
var control = (Control) container;
|
||||
var p = NodesWalker.Get().Parent( control ) as Control;
|
||||
|
||||
var pWidth = p == null ? UI.GetWindowWidth( control ) : UILayouting.GetWidth( p );
|
||||
|
@ -52,31 +158,37 @@ namespace Rokojori
|
|||
var y = p.Position.Y;
|
||||
|
||||
|
||||
if ( ! UINumber.IsNullOrNone( UIStyle.Left( region ) ))
|
||||
if ( ! UINumber.IsNullOrNone( container, UIStyleNumberProperty.Left ) )
|
||||
{
|
||||
var left = UINumber.Compute( control, UIStyle.Left( region ), 0 );
|
||||
var left = UINumber.Compute( control, UIStyleNumberProperty.Left, 0 );
|
||||
x = left;
|
||||
}
|
||||
else if ( ! UINumber.IsNullOrNone( UIStyle.Right( region ) ) )
|
||||
else if ( ! UINumber.IsNullOrNone( container, UIStyleNumberProperty.Right ) )
|
||||
{
|
||||
var right = UINumber.Compute( control, UIStyle.Right( region ), 0 );
|
||||
var right = UINumber.Compute( control, UIStyleNumberProperty.Right, 0 );
|
||||
x = ( pWidth - UILayouting.GetWidth( control ) ) - right;
|
||||
}
|
||||
|
||||
if ( ! UINumber.IsNullOrNone( UIStyle.Top( region ) ))
|
||||
if ( ! UINumber.IsNullOrNone( container, UIStyleNumberProperty.Top ))
|
||||
{
|
||||
var top = UINumber.Compute( control, UIStyle.Top( region ), 0 );
|
||||
var top = UINumber.Compute( control, UIStyleNumberProperty.Top, 0 );
|
||||
y = top;
|
||||
}
|
||||
else if ( ! UINumber.IsNullOrNone( UIStyle.Bottom( region ) ) )
|
||||
else if ( ! UINumber.IsNullOrNone( container, UIStyleNumberProperty.Bottom ) )
|
||||
{
|
||||
var bottom = UINumber.Compute( control, UIStyle.Bottom( region ), 0 );
|
||||
var bottom = UINumber.Compute( control, UIStyleNumberProperty.Bottom, 0 );
|
||||
y = ( pHeight - UILayouting.GetHeight( control ) ) - bottom;
|
||||
}
|
||||
|
||||
// var margin = UINumber.Compute( control, UIStyle.Margin( container ), 0 );
|
||||
// var marginLeft = margin + UINumber.Compute( control, UIStyle.MarginLeft( container ), 0 );
|
||||
// var marginTop = margin + UINumber.Compute( control, UIStyle.MarginRight( container ), 0 );
|
||||
// var marginRight = margin + UINumber.Compute( control, UIStyle.MarginRight( container ), 0 );
|
||||
// var marginBottom = margin + UINumber.Compute( control, UIStyle.MarginBottom( container ), 0 );
|
||||
|
||||
// UILayouting.SetPosition( control, new Vector2( x - ( marginLeft + marginRight ), y - ( marginTop + marginBottom ) ) );
|
||||
|
||||
UILayouting.SetPosition( control, new Vector2( x, y ) );
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void UpdatePivot( Control c )
|
||||
|
@ -88,18 +200,18 @@ namespace Rokojori
|
|||
|
||||
var container = c as UIStylePropertyContainer;
|
||||
|
||||
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 );
|
||||
var pivotX = UINumber.Compute( c, UIStyleNumberProperty.PivotX, 0.5f * c.Size.X, c.Size.X );
|
||||
var pivotY = UINumber.Compute( c, UIStyleNumberProperty.PivotY, 0.5f * c.Size.Y, c.Size.Y );
|
||||
|
||||
c.PivotOffset = new Vector2( pivotX, pivotY );
|
||||
|
||||
c.Rotation = UINumber.Compute( c, UIStyle.Rotation( container ), 0 );
|
||||
c.Rotation = UINumber.Compute( c, UIStyleNumberProperty.Rotation, 0 );
|
||||
|
||||
var scale = UINumber.Compute( c, UIStyle.Scale( container ), 1, 1 );
|
||||
var scale = UINumber.Compute( c, UIStyleNumberProperty.Scale, 1, 1 );
|
||||
|
||||
c.Scale = new Vector2(
|
||||
UINumber.Compute( c, UIStyle.ScaleX( container ), 1, 1 ) ,
|
||||
UINumber.Compute( c, UIStyle.ScaleY( container ), 1, 1 )
|
||||
UINumber.Compute( c, UIStyleNumberProperty.ScaleX, 1, 1 ) ,
|
||||
UINumber.Compute( c, UIStyleNumberProperty.ScaleY, 1, 1 )
|
||||
) * scale;
|
||||
|
||||
}
|
||||
|
@ -110,9 +222,9 @@ namespace Rokojori
|
|||
{
|
||||
var container = c as UIStylePropertyContainer;
|
||||
|
||||
var margin = UINumber.Compute( c, UIStyle.Margin( container ), 0 );
|
||||
var marginLeft = margin + UINumber.Compute( c, UIStyle.MarginLeft( container ), 0 );
|
||||
var marginTop = margin + UINumber.Compute( c, UIStyle.MarginTop( container ), 0 );
|
||||
var margin = UINumber.Compute( c, UIStyleNumberProperty.Margin, 0 );
|
||||
var marginLeft = margin + UINumber.Compute( c, UIStyleNumberProperty.MarginLeft, 0 );
|
||||
var marginTop = margin + UINumber.Compute( c, UIStyleNumberProperty.MarginTop, 0 );
|
||||
|
||||
position.X += marginLeft;
|
||||
position.Y += marginTop;
|
||||
|
@ -128,9 +240,9 @@ namespace Rokojori
|
|||
{
|
||||
var container = c as UIStylePropertyContainer;
|
||||
|
||||
var margin = UINumber.Compute( c, UIStyle.Margin( container ), 0 );
|
||||
var marginLeft = margin + UINumber.Compute( c, UIStyle.MarginLeft( container ), 0 );
|
||||
var marginRight = margin + UINumber.Compute( c, UIStyle.MarginRight( container ), 0 );
|
||||
var margin = UINumber.Compute( c, UIStyleNumberProperty.Margin, 0 );
|
||||
var marginLeft = margin + UINumber.Compute( c, UIStyleNumberProperty.MarginLeft, 0 );
|
||||
var marginRight = margin + UINumber.Compute( c, UIStyleNumberProperty.MarginRight, 0 );
|
||||
|
||||
return c.Size.X + marginLeft + marginRight;
|
||||
|
||||
|
@ -145,9 +257,9 @@ namespace Rokojori
|
|||
{
|
||||
var container = c as UIStylePropertyContainer;
|
||||
|
||||
var margin = UINumber.Compute( c, UIStyle.Margin( container ), 0 );
|
||||
var marginTop = margin + UINumber.Compute( c, UIStyle.MarginTop( container ), 0 );
|
||||
var marginBottom = margin + UINumber.Compute( c, UIStyle.MarginBottom( container ), 0 );
|
||||
var margin = UINumber.Compute( c, UIStyleNumberProperty.Margin, 0 );
|
||||
var marginTop = margin + UINumber.Compute( c, UIStyleNumberProperty.MarginTop, 0 );
|
||||
var marginBottom = margin + UINumber.Compute( c, UIStyleNumberProperty.MarginBottom, 0 );
|
||||
|
||||
return c.Size.Y + marginTop + marginBottom;
|
||||
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class UIBorderImage:NinePatchRect, UIStylePropertyContainer
|
||||
{
|
||||
[Export]
|
||||
public UIStyle parentStyle;
|
||||
|
||||
[ExportGroup("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;
|
||||
|
||||
|
||||
[ExportGroup( "Position" )]
|
||||
[Export]
|
||||
public UIPosition position;
|
||||
[Export]
|
||||
public UILineWrap lineWrap;
|
||||
[Export]
|
||||
public UINumber left;
|
||||
[Export]
|
||||
public UINumber top;
|
||||
[Export]
|
||||
public UINumber right;
|
||||
[Export]
|
||||
public UINumber bottom;
|
||||
|
||||
|
||||
[ExportGroup("Rotation & Scale")]
|
||||
[Export]
|
||||
public UINumber pivotX;
|
||||
[Export]
|
||||
public UINumber pivotY;
|
||||
|
||||
[Export]
|
||||
public UINumber rotation;
|
||||
|
||||
[Export]
|
||||
public UINumber scale;
|
||||
|
||||
[Export]
|
||||
public UINumber scaleX;
|
||||
[Export]
|
||||
public UINumber scaleY;
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,ColorPropertyName>> GetActiveShaderUIColorTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,FloatPropertyName>> GetActiveShaderUINumberTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
[ExportGroup("Transitions")]
|
||||
[Export]
|
||||
public TransitionSettingsAll transitionSettings;
|
||||
public TransitionSettingsAll GetTransitionSettingsAll()
|
||||
{
|
||||
return transitionSettings;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UINumberTransition[] numberTransitions;
|
||||
public UINumberTransition[] GetNumberTransitions()
|
||||
{
|
||||
return numberTransitions;
|
||||
}
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> activeNumberTransitions = new List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>>();
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> GetActiveUINumberTransitions()
|
||||
{
|
||||
return activeNumberTransitions;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UIColorTransition[] colorTransitions;
|
||||
public UIColorTransition[] GetColorTransitions()
|
||||
{
|
||||
return colorTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> activeColorTransitions = new List<ActiveStyleTransition<UIColor,UIStyleColorProperty>>();
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> GetActiveUIColorTransitions()
|
||||
{
|
||||
return activeColorTransitions;
|
||||
}
|
||||
|
||||
public UIStyle GetUIStyleParent()
|
||||
{
|
||||
return parentStyle;
|
||||
}
|
||||
|
||||
public UIPosition GetUIPosition()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
public UILineWrap GetUILineWrap()
|
||||
{
|
||||
return lineWrap;
|
||||
}
|
||||
|
||||
public UILayout GetUILayout()
|
||||
{
|
||||
return UILayout.___;
|
||||
}
|
||||
|
||||
public ShaderUIColor[] GetShaderUIColors()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ShaderUINumber[] GetShaderUINumbers()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public UIColor GetUIStyleColorProperty( UIStyleColorProperty property )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
case UIStyleNumberProperty.Left: return left;
|
||||
case UIStyleNumberProperty.Right: return right;
|
||||
case UIStyleNumberProperty.Top: return top;
|
||||
case UIStyleNumberProperty.Bottom: return bottom;
|
||||
|
||||
case UIStyleNumberProperty.PivotX: return pivotX;
|
||||
case UIStyleNumberProperty.PivotY: return pivotY;
|
||||
case UIStyleNumberProperty.Rotation: return rotation;
|
||||
|
||||
case UIStyleNumberProperty.Scale: return scale;
|
||||
case UIStyleNumberProperty.ScaleX: return scaleX;
|
||||
case UIStyleNumberProperty.ScaleY: return scaleY;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -11,7 +12,7 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UIStyle parentStyle;
|
||||
|
||||
[ExportCategory("Size & Margins")]
|
||||
[ExportGroup("Size & Margins")]
|
||||
[Export]
|
||||
public UINumber width;
|
||||
|
||||
|
@ -32,10 +33,12 @@ namespace Rokojori
|
|||
public UINumber marginBottom;
|
||||
|
||||
|
||||
[ExportCategory("Position")]
|
||||
[ExportGroup( "Position" )]
|
||||
[Export]
|
||||
public UIPosition position;
|
||||
[Export]
|
||||
public UILineWrap lineWrap;
|
||||
[Export]
|
||||
public UINumber left;
|
||||
[Export]
|
||||
public UINumber top;
|
||||
|
@ -45,7 +48,7 @@ namespace Rokojori
|
|||
public UINumber bottom;
|
||||
|
||||
|
||||
[ExportCategory("Rotation & Scale")]
|
||||
[ExportGroup( "Rotation & Scale" )]
|
||||
[Export]
|
||||
public UINumber pivotX;
|
||||
[Export]
|
||||
|
@ -62,6 +65,58 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UINumber scaleY;
|
||||
|
||||
[ExportGroup( "Shader Properties" )]
|
||||
[Export]
|
||||
public ShaderUIColor[] colorProperties;
|
||||
public List<ActiveStyleTransition<UIColor,ColorPropertyName>> activeShaderColorTransitions = new List<ActiveStyleTransition<UIColor,ColorPropertyName>>();
|
||||
public List<ActiveStyleTransition<UIColor,ColorPropertyName>> GetActiveShaderUIColorTransitions()
|
||||
{
|
||||
return activeShaderColorTransitions;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public ShaderUINumber[] numberProperties;
|
||||
public List<ActiveStyleTransition<UINumber,FloatPropertyName>> activeShaderNumberTransitions = new List<ActiveStyleTransition<UINumber,FloatPropertyName>>();
|
||||
public List<ActiveStyleTransition<UINumber,FloatPropertyName>> GetActiveShaderUINumberTransitions()
|
||||
{
|
||||
return activeShaderNumberTransitions;
|
||||
}
|
||||
|
||||
[ExportGroup("Transitions")]
|
||||
[Export]
|
||||
public TransitionSettingsAll transitionSettings;
|
||||
public TransitionSettingsAll GetTransitionSettingsAll()
|
||||
{
|
||||
return transitionSettings;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UINumberTransition[] numberTransitions;
|
||||
public UINumberTransition[] GetNumberTransitions()
|
||||
{
|
||||
return numberTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> activeNumberTransitions = new List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>>();
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> GetActiveUINumberTransitions()
|
||||
{
|
||||
return activeNumberTransitions;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UIColorTransition[] colorTransitions;
|
||||
public UIColorTransition[] GetColorTransitions()
|
||||
{
|
||||
return colorTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> activeColorTransitions = new List<ActiveStyleTransition<UIColor,UIStyleColorProperty>>();
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> GetActiveUIColorTransitions()
|
||||
{
|
||||
return activeColorTransitions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public UIStyle GetUIStyleParent()
|
||||
{
|
||||
|
@ -73,6 +128,27 @@ namespace Rokojori
|
|||
return position;
|
||||
}
|
||||
|
||||
public UILineWrap GetUILineWrap()
|
||||
{
|
||||
return lineWrap;
|
||||
}
|
||||
|
||||
public UILayout GetUILayout()
|
||||
{
|
||||
return UILayout.___;
|
||||
}
|
||||
|
||||
|
||||
public ShaderUIColor[] GetShaderUIColors()
|
||||
{
|
||||
return colorProperties;
|
||||
}
|
||||
|
||||
public ShaderUINumber[] GetShaderUINumbers()
|
||||
{
|
||||
return numberProperties;
|
||||
}
|
||||
|
||||
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
|
@ -104,5 +180,10 @@ namespace Rokojori
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public UIColor GetUIStyleColorProperty( UIStyleColorProperty property )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -10,7 +11,7 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UIStyle parentStyle;
|
||||
|
||||
[ExportCategory( "Layout" )]
|
||||
[ExportGroup( "Layout" )]
|
||||
[Export]
|
||||
public UILayout layout;
|
||||
|
||||
|
@ -18,6 +19,8 @@ namespace Rokojori
|
|||
public UINumber horizontalAlignment;
|
||||
[Export]
|
||||
public UINumber verticalAlignment;
|
||||
[Export]
|
||||
public UINumber verticalPlacement;
|
||||
|
||||
[Export]
|
||||
public UINumber elementSpacing;
|
||||
|
@ -25,7 +28,7 @@ namespace Rokojori
|
|||
public UINumber lineSpacing;
|
||||
|
||||
|
||||
[ExportCategory( "Size & Margins" )]
|
||||
[ExportGroup( "Size & Margins" )]
|
||||
[Export]
|
||||
public UINumber width;
|
||||
[Export]
|
||||
|
@ -44,7 +47,22 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UINumber marginBottom;
|
||||
|
||||
[ExportCategory( "Font" )]
|
||||
|
||||
[ExportGroup( "Position" )]
|
||||
[Export]
|
||||
public UIPosition position;
|
||||
[Export]
|
||||
public UILineWrap lineWrap;
|
||||
[Export]
|
||||
public UINumber left;
|
||||
[Export]
|
||||
public UINumber top;
|
||||
[Export]
|
||||
public UINumber right;
|
||||
[Export]
|
||||
public UINumber bottom;
|
||||
|
||||
[ExportGroup( "Font" )]
|
||||
[Export]
|
||||
public Font font;
|
||||
[Export]
|
||||
|
@ -62,20 +80,55 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UIColor shadowColor;
|
||||
|
||||
[Export]
|
||||
public UINumber shadowOffsetX;
|
||||
[Export]
|
||||
public UINumber shadowOffsetY;
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,ColorPropertyName>> GetActiveShaderUIColorTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,FloatPropertyName>> GetActiveShaderUINumberTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
[ExportCategory( "Position" )]
|
||||
[ExportGroup("Transitions")]
|
||||
[Export]
|
||||
public UIPosition position;
|
||||
[Export]
|
||||
public UINumber left;
|
||||
[Export]
|
||||
public UINumber top;
|
||||
[Export]
|
||||
public UINumber right;
|
||||
[Export]
|
||||
public UINumber bottom;
|
||||
public TransitionSettingsAll transitionSettings;
|
||||
public TransitionSettingsAll GetTransitionSettingsAll()
|
||||
{
|
||||
return transitionSettings;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UINumberTransition[] numberTransitions;
|
||||
public UINumberTransition[] GetNumberTransitions()
|
||||
{
|
||||
return numberTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> activeNumberTransitions = new List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>>();
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> GetActiveUINumberTransitions()
|
||||
{
|
||||
return activeNumberTransitions;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UIColorTransition[] colorTransitions;
|
||||
public UIColorTransition[] GetColorTransitions()
|
||||
{
|
||||
return colorTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> activeColorTransitions = new List<ActiveStyleTransition<UIColor,UIStyleColorProperty>>();
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> GetActiveUIColorTransitions()
|
||||
{
|
||||
return activeColorTransitions;
|
||||
}
|
||||
|
||||
public UIStyle GetUIStyleParent()
|
||||
{
|
||||
|
@ -87,6 +140,26 @@ namespace Rokojori
|
|||
return position;
|
||||
}
|
||||
|
||||
public UILineWrap GetUILineWrap()
|
||||
{
|
||||
return lineWrap;
|
||||
}
|
||||
|
||||
public UILayout GetUILayout()
|
||||
{
|
||||
return layout;
|
||||
}
|
||||
|
||||
public ShaderUIColor[] GetShaderUIColors()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ShaderUINumber[] GetShaderUINumbers()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
|
@ -99,7 +172,9 @@ namespace Rokojori
|
|||
case UIStyleNumberProperty.Width: return width;
|
||||
case UIStyleNumberProperty.Height: return height;
|
||||
|
||||
|
||||
case UIStyleNumberProperty.HorizontalAlignment: return horizontalAlignment;
|
||||
case UIStyleNumberProperty.VerticalAlignment: return verticalAlignment;
|
||||
case UIStyleNumberProperty.VerticalPlacement: return verticalPlacement;
|
||||
case UIStyleNumberProperty.ElementSpacing: return elementSpacing;
|
||||
case UIStyleNumberProperty.LineSpacing: return lineSpacing;
|
||||
|
||||
|
@ -109,20 +184,48 @@ namespace Rokojori
|
|||
case UIStyleNumberProperty.MarginRight: return marginRight;
|
||||
case UIStyleNumberProperty.MarginTop: return marginTop;
|
||||
case UIStyleNumberProperty.MarginBottom: return marginBottom;
|
||||
|
||||
case UIStyleNumberProperty.FontSize: return fontSize;
|
||||
case UIStyleNumberProperty.FontOutlineSize: return outlineSize;
|
||||
case UIStyleNumberProperty.FontShadowSize: return shadowSize;
|
||||
case UIStyleNumberProperty.FontShadowOffsetX: return shadowOffsetX;
|
||||
case UIStyleNumberProperty.FontShadowOffsetY: return shadowOffsetY;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public UIColor GetUIStyleColorProperty( UIStyleColorProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
{
|
||||
case UIStyleColorProperty.FontColor: return fontColor;
|
||||
case UIStyleColorProperty.FontOutlineColor: return outlineColor;
|
||||
case UIStyleColorProperty.FontShadowColor: return shadowColor;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Layout()
|
||||
{
|
||||
var layout = UIStyle.Layout( this );
|
||||
|
||||
switch ( layout )
|
||||
{
|
||||
case UILayout.Flow_Left_Top: UIFlowLayout.Apply( this ); break;
|
||||
case UILayout.___:
|
||||
case UILayout.Flow_Left_Top:
|
||||
{
|
||||
UIFlowLayout.Apply( this );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 contentSize = Vector2.Zero;
|
||||
public Vector2 contentOffset = Vector2.Zero;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -11,10 +12,30 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UIStyle parentStyle;
|
||||
|
||||
[ExportGroup( "Font" )]
|
||||
[Export]
|
||||
public Font font;
|
||||
[Export]
|
||||
public UINumber fontSize;
|
||||
[Export]
|
||||
public UIColor fontColor;
|
||||
|
||||
[ExportCategory("Size & Margins")]
|
||||
[Export]
|
||||
public UINumber outlineSize;
|
||||
[Export]
|
||||
public UIColor outlineColor;
|
||||
|
||||
[Export]
|
||||
public UINumber shadowSize;
|
||||
[Export]
|
||||
public UIColor shadowColor;
|
||||
|
||||
[Export]
|
||||
public UINumber shadowOffsetX;
|
||||
[Export]
|
||||
public UINumber shadowOffsetY;
|
||||
|
||||
[ExportGroup("Size & Margins")]
|
||||
[Export]
|
||||
public UINumber width;
|
||||
|
||||
|
@ -35,10 +56,12 @@ namespace Rokojori
|
|||
public UINumber marginBottom;
|
||||
|
||||
|
||||
[ExportCategory("Position")]
|
||||
[ExportGroup( "Position" )]
|
||||
[Export]
|
||||
public UIPosition position;
|
||||
[Export]
|
||||
public UILineWrap lineWrap;
|
||||
[Export]
|
||||
public UINumber left;
|
||||
[Export]
|
||||
public UINumber top;
|
||||
|
@ -48,7 +71,7 @@ namespace Rokojori
|
|||
public UINumber bottom;
|
||||
|
||||
|
||||
[ExportCategory("Rotation & Scale")]
|
||||
[ExportGroup("Rotation & Scale")]
|
||||
[Export]
|
||||
public UINumber pivotX;
|
||||
[Export]
|
||||
|
@ -65,6 +88,72 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UINumber scaleY;
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,ColorPropertyName>> GetActiveShaderUIColorTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,FloatPropertyName>> GetActiveShaderUINumberTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
[ExportGroup("Transitions")]
|
||||
[Export]
|
||||
public TransitionSettingsAll transitionSettings;
|
||||
public TransitionSettingsAll GetTransitionSettingsAll()
|
||||
{
|
||||
return transitionSettings;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UINumberTransition[] numberTransitions;
|
||||
public UINumberTransition[] GetNumberTransitions()
|
||||
{
|
||||
return numberTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> activeNumberTransitions = new List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>>();
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> GetActiveUINumberTransitions()
|
||||
{
|
||||
return activeNumberTransitions;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UIColorTransition[] colorTransitions;
|
||||
public UIColorTransition[] GetColorTransitions()
|
||||
{
|
||||
return colorTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> activeColorTransitions = new List<ActiveStyleTransition<UIColor,UIStyleColorProperty>>();
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> GetActiveUIColorTransitions()
|
||||
{
|
||||
return activeColorTransitions;
|
||||
}
|
||||
|
||||
LabelSettings _labelSettings;
|
||||
|
||||
public LabelSettings uiTextLabelSettings
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( _labelSettings == null )
|
||||
{
|
||||
_labelSettings = new LabelSettings();
|
||||
}
|
||||
|
||||
LabelSettings = _labelSettings;
|
||||
return _labelSettings;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_labelSettings = value.Duplicate() as LabelSettings;
|
||||
LabelSettings = _labelSettings;
|
||||
}
|
||||
}
|
||||
|
||||
public UIStyle GetUIStyleParent()
|
||||
{
|
||||
return parentStyle;
|
||||
|
@ -75,6 +164,28 @@ namespace Rokojori
|
|||
return position;
|
||||
}
|
||||
|
||||
public UILineWrap GetUILineWrap()
|
||||
{
|
||||
return lineWrap;
|
||||
}
|
||||
|
||||
public UILayout GetUILayout()
|
||||
{
|
||||
return UILayout.___;
|
||||
}
|
||||
|
||||
public ShaderUIColor[] GetShaderUIColors()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ShaderUINumber[] GetShaderUINumbers()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
|
@ -102,6 +213,24 @@ namespace Rokojori
|
|||
case UIStyleNumberProperty.Scale: return scale;
|
||||
case UIStyleNumberProperty.ScaleX: return scaleX;
|
||||
case UIStyleNumberProperty.ScaleY: return scaleY;
|
||||
|
||||
case UIStyleNumberProperty.FontSize: return fontSize;
|
||||
case UIStyleNumberProperty.FontOutlineSize: return outlineSize;
|
||||
case UIStyleNumberProperty.FontShadowSize: return shadowSize;
|
||||
case UIStyleNumberProperty.FontShadowOffsetX: return shadowOffsetX;
|
||||
case UIStyleNumberProperty.FontShadowOffsetY: return shadowOffsetY;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public UIColor GetUIStyleColorProperty( UIStyleColorProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
{
|
||||
case UIStyleColorProperty.FontColor: return fontColor;
|
||||
case UIStyleColorProperty.FontOutlineColor: return outlineColor;
|
||||
case UIStyleColorProperty.FontShadowColor: return shadowColor;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class OnSliderValueChange : Node
|
||||
{
|
||||
[Export]
|
||||
public HSlider slider;
|
||||
HSlider _connectedSlider = null;
|
||||
|
||||
[Export]
|
||||
public RJAction onChange;
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if ( _connectedSlider == slider )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( _connectedSlider != null )
|
||||
{
|
||||
_connectedSlider.Changed -= OnChanged;
|
||||
}
|
||||
|
||||
_connectedSlider = slider;
|
||||
|
||||
|
||||
if ( _connectedSlider != null )
|
||||
{
|
||||
_connectedSlider.Changed += OnChanged;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OnChanged()
|
||||
{
|
||||
Actions.Trigger( onChange );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[gd_resource type="Resource" script_class="FloatPropertyName" load_steps=2 format=3 uid="uid://v423srfwpna8"]
|
||||
|
||||
[ext_resource type="Script" path="res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Properties/FloatPropertyName.cs" id="1_4guhd"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_4guhd")
|
||||
propertyName = "borderRadius"
|
|
@ -0,0 +1,7 @@
|
|||
[gd_resource type="Resource" script_class="FloatPropertyName" load_steps=2 format=3 uid="uid://dbg2rgj5s7uqn"]
|
||||
|
||||
[ext_resource type="Script" path="res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Properties/FloatPropertyName.cs" id="1_2hnh6"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_2hnh6")
|
||||
propertyName = "offset"
|
|
@ -0,0 +1,7 @@
|
|||
[gd_resource type="Resource" script_class="FloatPropertyName" load_steps=2 format=3 uid="uid://dngbeoiix72sf"]
|
||||
|
||||
[ext_resource type="Script" path="res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Properties/FloatPropertyName.cs" id="1_0sf2s"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_0sf2s")
|
||||
propertyName = "strokeSize"
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ShaderUIColor : Resource
|
||||
{
|
||||
[Export]
|
||||
public ColorPropertyName colorPropertyName;
|
||||
|
||||
[Export]
|
||||
public UIColor color;
|
||||
|
||||
public void UpdateMaterial( UIStylePropertyContainer container, Material material )
|
||||
{
|
||||
var colorValue = UIColor.Compute( container as Control, color, Colors.White );
|
||||
colorPropertyName.Set( material, colorValue );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class ShaderUINumber : Resource
|
||||
{
|
||||
[Export]
|
||||
public FloatPropertyName floatPropertyName;
|
||||
|
||||
[Export]
|
||||
public UINumber number;
|
||||
|
||||
[Export]
|
||||
public TransitionSettings transitionSettings;
|
||||
|
||||
public void UpdateMaterial( UIStylePropertyContainer container, Material material )
|
||||
{
|
||||
var control = container as Control;
|
||||
var numberValue = UINumber.Compute( container as Control, number, 0f );
|
||||
|
||||
var allSettings = UIStyle.GetTransitionSettingsAll( container );
|
||||
var usesTransition = transitionSettings != null || allSettings != null && allSettings.transitionAllProperties;
|
||||
|
||||
if ( ! usesTransition )
|
||||
{
|
||||
floatPropertyName.Set( material, numberValue );
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
var transitionValue = ActiveStyleTransition<UINumber,FloatPropertyName>.ProcessTransition<float>(
|
||||
container, numberValue, container.GetActiveShaderUINumberTransitions(),
|
||||
number, floatPropertyName,
|
||||
()=>{ return UIStyle.GetTransitionSettings( container ); }
|
||||
|
||||
);
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public partial class UIShaderProperties
|
||||
{
|
||||
public static void UpdateProperties( UIStylePropertyContainer container, Material material )
|
||||
{
|
||||
var numbers = container.GetShaderUINumbers();
|
||||
|
||||
if ( numbers != null )
|
||||
{
|
||||
foreach ( var n in numbers )
|
||||
{
|
||||
if ( n == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
n.UpdateMaterial( container, material );
|
||||
}
|
||||
}
|
||||
|
||||
var colors = container.GetShaderUIColors();
|
||||
|
||||
if ( colors != null )
|
||||
{
|
||||
foreach ( var c in colors )
|
||||
{
|
||||
if ( c == null )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
c.UpdateMaterial( container, material );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[gd_resource type="Resource" script_class="Vector2PropertyName" load_steps=2 format=3 uid="uid://bhy8b3gopkq4m"]
|
||||
|
||||
[ext_resource type="Script" path="res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Properties/Vector2PropertyName.cs" id="1_t5csl"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_t5csl")
|
||||
propertyName = "size"
|
|
@ -4,12 +4,129 @@ using Rokojori;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum UIColorAnimationBlend
|
||||
{
|
||||
Multiply,
|
||||
Add,
|
||||
Replace
|
||||
}
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class UIColor : Resource
|
||||
{
|
||||
[Export]
|
||||
public Color color;
|
||||
public Color color = Colors.White;
|
||||
|
||||
[Export]
|
||||
public bool isAnimated = false;
|
||||
|
||||
[Export]
|
||||
public Gradient animationGradient;
|
||||
|
||||
[Export]
|
||||
public ColorBlendModeType blendMode = ColorBlendModeType.Multiply;
|
||||
|
||||
[Export]
|
||||
public float animationDuration = 1;
|
||||
|
||||
[Export]
|
||||
public float animationOffset = 0;
|
||||
|
||||
[Export]
|
||||
public RJTimeLine timeLine;
|
||||
|
||||
public static Color Compute( Control control, UIStyleColorProperty property, Color defaultColor )
|
||||
{
|
||||
var container = control as UIStylePropertyContainer;
|
||||
var transition = UIStyle.GetTransition( container, property );
|
||||
|
||||
var uiColor = UIStyle.GetUIColorProperty( control as UIStylePropertyContainer, property );
|
||||
var computedColor = Compute( control, uiColor, defaultColor );
|
||||
|
||||
var allSettings = UIStyle.GetTransitionSettingsAll( container );
|
||||
|
||||
var usesTransition = transition != null || allSettings != null && allSettings.transitionAllProperties;
|
||||
|
||||
if ( ! usesTransition )
|
||||
{
|
||||
return computedColor;
|
||||
}
|
||||
|
||||
var activeNumberTransitions = container.GetActiveUIColorTransitions();
|
||||
|
||||
var propertyTransition = activeNumberTransitions.Find( t => t != null && t.propertyType == property );
|
||||
|
||||
if ( propertyTransition == null )
|
||||
{
|
||||
propertyTransition = new ActiveStyleTransition<UIColor, UIStyleColorProperty>();
|
||||
propertyTransition.propertyType = property;
|
||||
propertyTransition.value = uiColor;
|
||||
propertyTransition.transitioning = false;
|
||||
|
||||
activeNumberTransitions.Add( propertyTransition );
|
||||
|
||||
return computedColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if ( propertyTransition.value != uiColor && ! propertyTransition.transitioning && UIStyle.GetTransitionSettings( container, property ) != null)
|
||||
{
|
||||
var transitionSettings = UIStyle.GetTransitionSettings( container, property );
|
||||
propertyTransition.timeLine = transitionSettings.timeLine;
|
||||
propertyTransition.start = TimeLineManager.GetPosition( transitionSettings.timeLine );
|
||||
propertyTransition.end = propertyTransition.start + transitionSettings.duration;
|
||||
propertyTransition.transitioning = true;
|
||||
propertyTransition.curve = transitionSettings.curve;
|
||||
}
|
||||
}
|
||||
|
||||
if ( propertyTransition.value == uiColor )
|
||||
{
|
||||
propertyTransition.transitioning = false;
|
||||
return computedColor;
|
||||
}
|
||||
|
||||
var computedTransitionValue = Compute( control, propertyTransition.value, defaultColor );
|
||||
|
||||
var transitionPhase = TimeLineManager.GetRangePhase( propertyTransition.timeLine, propertyTransition.start, propertyTransition.end );
|
||||
|
||||
if ( transitionPhase >= 1 )
|
||||
{
|
||||
activeNumberTransitions.Remove( propertyTransition );
|
||||
}
|
||||
|
||||
var amount = MathX.Clamp01( transitionPhase );
|
||||
var curveAmount = amount;
|
||||
|
||||
if ( propertyTransition.curve != null )
|
||||
{
|
||||
curveAmount = propertyTransition.curve.Sample( curveAmount );
|
||||
}
|
||||
|
||||
return ColorX.Lerp( computedTransitionValue, computedColor, curveAmount );
|
||||
}
|
||||
|
||||
public static Color Compute( Control control, UIColor color, Color defaultColor )
|
||||
{
|
||||
if ( color == null )
|
||||
{
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
if ( ! color.isAnimated || color.animationGradient == null )
|
||||
{
|
||||
return color.color;
|
||||
}
|
||||
|
||||
var phase = TimeLineManager.GetPhase( color.timeLine, color.animationDuration, color.animationOffset );
|
||||
|
||||
var gradientColor = color.animationGradient.Sample( phase );
|
||||
|
||||
return ColorBlendMode.Blend( color.blendMode, color.color, gradientColor );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public enum UILineWrap
|
||||
{
|
||||
___,
|
||||
Wrap_On_Overflow,
|
||||
Wrap_Always,
|
||||
Wrap_Never
|
||||
}
|
||||
}
|
||||
|
|
@ -15,15 +15,36 @@ namespace Rokojori
|
|||
[Export]
|
||||
public string unit = "";
|
||||
|
||||
[ExportGroup("Animation")]
|
||||
|
||||
[Export]
|
||||
public bool isAnimated;
|
||||
|
||||
[Export]
|
||||
public Curve animationCurve;
|
||||
|
||||
[Export]
|
||||
public float animationDuration;
|
||||
|
||||
[Export]
|
||||
public float animationOffset;
|
||||
|
||||
[Export]
|
||||
public RJTimeLine timeLine;
|
||||
|
||||
public bool IsNone => unit == "none";
|
||||
|
||||
public float Compute( Control control, float alternative )
|
||||
public float ComputeRaw( Control control, float alternative )
|
||||
{
|
||||
return UINumber.Compute( control, this, alternative );
|
||||
}
|
||||
|
||||
|
||||
public static bool IsNullOrNone( UIStylePropertyContainer container, UIStyleNumberProperty property )
|
||||
{
|
||||
return IsNullOrNone( UIStyle.GetUINumberProperty( container, property ) );
|
||||
}
|
||||
|
||||
public static bool IsNullOrNone( UINumber number )
|
||||
{
|
||||
if ( number == null )
|
||||
|
@ -34,6 +55,154 @@ namespace Rokojori
|
|||
return number.IsNone;
|
||||
}
|
||||
|
||||
public static int ComputeInt( Control control, UINumber number, float alternative = 0, float relative = 100 )
|
||||
{
|
||||
return Mathf.RoundToInt( Compute( control, number, alternative, relative ) );
|
||||
}
|
||||
|
||||
public static int ComputeInt( Control control, UIStyleNumberProperty property, float alternative = 0, float relative = 100 )
|
||||
{
|
||||
return Mathf.RoundToInt( Compute( control, property, alternative, relative ) );
|
||||
}
|
||||
|
||||
public bool Equals( UINumber other )
|
||||
{
|
||||
if ( other == this )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( other == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( other.value != value )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( other.unit != unit )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( other.isAnimated != isAnimated )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( other.animationCurve != animationCurve )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( other.animationDuration != animationDuration )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( other.animationOffset != animationOffset )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( other.timeLine != timeLine )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public void CopyForm( UINumber other )
|
||||
{
|
||||
if ( other == this )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
value = other.value;
|
||||
unit = other.unit;
|
||||
isAnimated = other.isAnimated;
|
||||
animationCurve = other.animationCurve;
|
||||
animationDuration = other.animationDuration;
|
||||
animationOffset = other.animationOffset;
|
||||
timeLine = other.timeLine;
|
||||
}
|
||||
|
||||
public static float Compute( Control control, UIStyleNumberProperty property, float alternative = 0, float relative = 100 )
|
||||
{
|
||||
var container = control as UIStylePropertyContainer;
|
||||
var transition = UIStyle.GetTransition( container, property );
|
||||
|
||||
var number = UIStyle.GetUINumberProperty( control as UIStylePropertyContainer, property );
|
||||
var computedValue = Compute( control, number, alternative, relative );
|
||||
|
||||
var allSettings = UIStyle.GetTransitionSettingsAll( container );
|
||||
|
||||
var usesTransition = transition != null || allSettings != null && allSettings.transitionAllProperties;
|
||||
|
||||
if ( ! usesTransition )
|
||||
{
|
||||
return computedValue;
|
||||
}
|
||||
|
||||
var activeNumberTransitions = container.GetActiveUINumberTransitions();
|
||||
|
||||
var propertyTransition = activeNumberTransitions.Find( t => t != null && t.propertyType == property );
|
||||
|
||||
if ( propertyTransition == null )
|
||||
{
|
||||
propertyTransition = new ActiveStyleTransition<UINumber, UIStyleNumberProperty>();
|
||||
propertyTransition.propertyType = property;
|
||||
propertyTransition.value = number;
|
||||
propertyTransition.transitioning = false;
|
||||
|
||||
activeNumberTransitions.Add( propertyTransition );
|
||||
|
||||
return computedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( propertyTransition.value != number && ! propertyTransition.transitioning && UIStyle.GetTransitionSettings( container, property ) != null )
|
||||
{
|
||||
var transitionSettings = UIStyle.GetTransitionSettings( container, property );
|
||||
propertyTransition.timeLine = transitionSettings.timeLine;
|
||||
propertyTransition.start = TimeLineManager.GetPosition( transitionSettings.timeLine );
|
||||
propertyTransition.end = propertyTransition.start + transitionSettings.duration;
|
||||
propertyTransition.transitioning = true;
|
||||
propertyTransition.curve = transitionSettings.curve;
|
||||
}
|
||||
}
|
||||
|
||||
if ( propertyTransition.value == number )
|
||||
{
|
||||
propertyTransition.transitioning = false;
|
||||
return computedValue;
|
||||
}
|
||||
|
||||
var computedTransitionValue = Compute( control, propertyTransition.value, alternative, relative );
|
||||
|
||||
var transitionPhase = TimeLineManager.GetRangePhase( propertyTransition.timeLine, propertyTransition.start, propertyTransition.end );
|
||||
|
||||
if ( transitionPhase >= 1 )
|
||||
{
|
||||
activeNumberTransitions.Remove( propertyTransition );
|
||||
}
|
||||
|
||||
var amount = MathX.Clamp01( transitionPhase );
|
||||
var curveAmount = amount;
|
||||
|
||||
if ( propertyTransition.curve != null )
|
||||
{
|
||||
curveAmount = propertyTransition.curve.Sample( curveAmount );
|
||||
}
|
||||
|
||||
return Mathf.Lerp( computedTransitionValue, computedValue, curveAmount );
|
||||
}
|
||||
|
||||
|
||||
public static float Compute( Control control, UINumber number, float alternative = 0, float relative = 100 )
|
||||
{
|
||||
|
@ -52,12 +221,27 @@ namespace Rokojori
|
|||
|
||||
static UI _ui;
|
||||
|
||||
static float em()
|
||||
public static float em()
|
||||
{
|
||||
return _ui == null ? 12 : _ui.X_computedFontSizePixels;
|
||||
}
|
||||
|
||||
public static float Compute( Control control, UINumber number, float width, float height, float relative )
|
||||
{
|
||||
var value = ComputeWithoutAnimation( control, number, width, height, relative );
|
||||
|
||||
if ( ! number.isAnimated || number.animationCurve == null )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
var phase = TimeLineManager.GetPhase( number.timeLine, number.animationDuration, number.animationOffset );
|
||||
|
||||
return number.animationCurve.Sample( phase ) * value;
|
||||
|
||||
}
|
||||
|
||||
static float ComputeWithoutAnimation( Control control, UINumber number, float width, float height, float relative )
|
||||
{
|
||||
if ( number == null )
|
||||
{
|
||||
|
@ -92,13 +276,37 @@ namespace Rokojori
|
|||
return number.value / 100f * ( parent == null ? width : parent.Size.X );
|
||||
}
|
||||
|
||||
case "cw":
|
||||
{
|
||||
var parent = control.GetParent<Control>();
|
||||
return number.value / 100f * ( parent == null ? width : UILayouting.GetContentSize( parent ).X );
|
||||
}
|
||||
|
||||
case "ch":
|
||||
{
|
||||
var parent = control.GetParent<Control>();
|
||||
return number.value / 100f * ( parent == null ? height : UILayouting.GetContentSize( parent ).Y );
|
||||
}
|
||||
|
||||
case "cx":
|
||||
{
|
||||
var parent = control.GetParent<Control>();
|
||||
return number.value / 100f * ( parent == null ? 0 : UILayouting.GetContentOffset( parent ).X );
|
||||
}
|
||||
|
||||
case "cy":
|
||||
{
|
||||
var parent = control.GetParent<Control>();
|
||||
return number.value / 100f * ( parent == null ? 0 : UILayouting.GetContentOffset( parent ).Y );
|
||||
}
|
||||
|
||||
case "ph":
|
||||
{
|
||||
var parent = control.GetParent<Control>();
|
||||
return number.value / 100f * ( parent == null ? height : parent.Size.Y );
|
||||
}
|
||||
|
||||
case "px": case "":
|
||||
case "":
|
||||
{
|
||||
return number.value;
|
||||
}
|
||||
|
@ -111,13 +319,22 @@ namespace Rokojori
|
|||
|
||||
var expression = new Expression();
|
||||
|
||||
|
||||
var expressionText = number.unit == null ? "" : RegexUtility.Replace( number.unit, "%", " * relative " );
|
||||
var parseResult = expression.Parse( expressionText,
|
||||
new string[]
|
||||
{
|
||||
"em","vw", "vh", "pw", "ph", "px", "relative", "value" }
|
||||
);
|
||||
"em",
|
||||
|
||||
"vw", "vh",
|
||||
"pw", "ph",
|
||||
|
||||
"cw","ch",
|
||||
"cx","cy",
|
||||
|
||||
"relative",
|
||||
"value"
|
||||
}
|
||||
);
|
||||
|
||||
if ( Error.Ok != parseResult )
|
||||
{
|
||||
|
@ -128,14 +345,26 @@ namespace Rokojori
|
|||
|
||||
var inputs = new Godot.Collections.Array();
|
||||
inputs.Add( em() );
|
||||
inputs.Add( width / 100f );
|
||||
inputs.Add( height / 100f );
|
||||
|
||||
// vw, vh
|
||||
inputs.Add( width / 100f ); inputs.Add( height / 100f );
|
||||
|
||||
// pw, ph
|
||||
inputs.Add( ( parentControl == null ? width : parentControl.Size.X ) / 100f );
|
||||
inputs.Add( ( parentControl == null ? height : parentControl.Size.Y ) / 100f );
|
||||
inputs.Add( 1 );
|
||||
|
||||
// cw, ch
|
||||
inputs.Add( ( parentControl == null ? width : UILayouting.GetContentSize( parentControl ).X ) / 100f );
|
||||
inputs.Add( ( parentControl == null ? width : UILayouting.GetContentSize( parentControl ).Y ) / 100f );
|
||||
|
||||
// cx, cy
|
||||
inputs.Add( ( parentControl == null ? 0 : UILayouting.GetContentOffset( parentControl ).X ) / 100f );
|
||||
inputs.Add( ( parentControl == null ? 0 : UILayouting.GetContentOffset( parentControl ).Y ) / 100f );
|
||||
|
||||
// "relative"
|
||||
inputs.Add( relative / 100f );
|
||||
|
||||
|
||||
// value
|
||||
if ( number.unit.IndexOf( "value" ) == -1 )
|
||||
{
|
||||
inputs.Add( 0 );
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -12,7 +13,7 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UIStyle parentStyle;
|
||||
|
||||
[ExportCategory( "Layout" )]
|
||||
[ExportGroup( "Layout" )]
|
||||
[Export]
|
||||
public UILayout layout;
|
||||
|
||||
|
@ -20,6 +21,8 @@ namespace Rokojori
|
|||
public UINumber horizontalAlignment;
|
||||
[Export]
|
||||
public UINumber verticalAlignment;
|
||||
[Export]
|
||||
public UINumber verticalPlacement;
|
||||
|
||||
[Export]
|
||||
public UINumber elementSpacing;
|
||||
|
@ -27,7 +30,7 @@ namespace Rokojori
|
|||
public UINumber lineSpacing;
|
||||
|
||||
|
||||
[ExportCategory( "Size & Margins" )]
|
||||
[ExportGroup( "Size & Margins" )]
|
||||
[Export]
|
||||
public UINumber width;
|
||||
[Export]
|
||||
|
@ -46,7 +49,7 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UINumber marginBottom;
|
||||
|
||||
[ExportCategory( "Font" )]
|
||||
[ExportGroup( "Font" )]
|
||||
[Export]
|
||||
public Font font;
|
||||
[Export]
|
||||
|
@ -64,10 +67,17 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UIColor shadowColor;
|
||||
|
||||
[ExportCategory( "Position" )]
|
||||
[Export]
|
||||
public UINumber shadowOffsetX;
|
||||
[Export]
|
||||
public UINumber shadowOffsetY;
|
||||
|
||||
[ExportGroup( "Position" )]
|
||||
[Export]
|
||||
public UIPosition position;
|
||||
[Export]
|
||||
public UILineWrap lineWrap;
|
||||
[Export]
|
||||
public UINumber left;
|
||||
[Export]
|
||||
public UINumber top;
|
||||
|
@ -76,6 +86,73 @@ namespace Rokojori
|
|||
[Export]
|
||||
public UINumber bottom;
|
||||
|
||||
[ExportGroup("Rotation & Scale")]
|
||||
[Export]
|
||||
public UINumber pivotX;
|
||||
[Export]
|
||||
public UINumber pivotY;
|
||||
|
||||
[Export]
|
||||
public UINumber rotation;
|
||||
|
||||
[Export]
|
||||
public UINumber scale;
|
||||
|
||||
[Export]
|
||||
public UINumber scaleX;
|
||||
[Export]
|
||||
public UINumber scaleY;
|
||||
|
||||
[ExportGroup( "Shader Properties" )]
|
||||
[Export]
|
||||
public ShaderUIColor[] colorProperties;
|
||||
[Export]
|
||||
public ShaderUINumber[] numberProperties;
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,ColorPropertyName>> GetActiveShaderUIColorTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,FloatPropertyName>> GetActiveShaderUINumberTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
[ExportGroup("Transitions")]
|
||||
[Export]
|
||||
public TransitionSettingsAll transitionSettings;
|
||||
public TransitionSettingsAll GetTransitionSettingsAll()
|
||||
{
|
||||
return transitionSettings;
|
||||
}
|
||||
|
||||
[Export]
|
||||
public UINumberTransition[] numberTransitions;
|
||||
public UINumberTransition[] GetNumberTransitions()
|
||||
{
|
||||
return numberTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> GetActiveUINumberTransitions()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
[Export]
|
||||
public UIColorTransition[] colorTransitions;
|
||||
public UIColorTransition[] GetColorTransitions()
|
||||
{
|
||||
return colorTransitions;
|
||||
}
|
||||
|
||||
public List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> GetActiveUIColorTransitions()
|
||||
{
|
||||
return null;;
|
||||
}
|
||||
|
||||
|
||||
public UIStyle GetUIStyleParent()
|
||||
{
|
||||
return parentStyle;
|
||||
|
@ -86,6 +163,26 @@ namespace Rokojori
|
|||
return position;
|
||||
}
|
||||
|
||||
public UILineWrap GetUILineWrap()
|
||||
{
|
||||
return lineWrap;
|
||||
}
|
||||
|
||||
public UILayout GetUILayout()
|
||||
{
|
||||
return layout;
|
||||
}
|
||||
|
||||
public ShaderUIColor[] GetShaderUIColors()
|
||||
{
|
||||
return colorProperties;
|
||||
}
|
||||
|
||||
public ShaderUINumber[] GetShaderUINumbers()
|
||||
{
|
||||
return numberProperties;
|
||||
}
|
||||
|
||||
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
|
@ -95,6 +192,9 @@ namespace Rokojori
|
|||
case UIStyleNumberProperty.Top: return top;
|
||||
case UIStyleNumberProperty.Bottom: return bottom;
|
||||
|
||||
case UIStyleNumberProperty.HorizontalAlignment: return horizontalAlignment;
|
||||
case UIStyleNumberProperty.VerticalAlignment: return verticalAlignment;
|
||||
case UIStyleNumberProperty.VerticalPlacement: return verticalPlacement;
|
||||
case UIStyleNumberProperty.ElementSpacing: return elementSpacing;
|
||||
case UIStyleNumberProperty.LineSpacing: return lineSpacing;
|
||||
|
||||
|
@ -102,12 +202,40 @@ namespace Rokojori
|
|||
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;
|
||||
|
||||
case UIStyleNumberProperty.FontSize: return fontSize;
|
||||
case UIStyleNumberProperty.FontOutlineSize: return outlineSize;
|
||||
case UIStyleNumberProperty.FontShadowSize: return shadowSize;
|
||||
case UIStyleNumberProperty.FontShadowOffsetX: return shadowOffsetX;
|
||||
case UIStyleNumberProperty.FontShadowOffsetY: return shadowOffsetY;
|
||||
|
||||
case UIStyleNumberProperty.PivotX: return pivotX;
|
||||
case UIStyleNumberProperty.PivotY: return pivotY;
|
||||
case UIStyleNumberProperty.Rotation: return rotation;
|
||||
|
||||
case UIStyleNumberProperty.Scale: return scale;
|
||||
case UIStyleNumberProperty.ScaleX: return scaleX;
|
||||
case UIStyleNumberProperty.ScaleY: return scaleY;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public UIColor GetUIStyleColorProperty( UIStyleColorProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
{
|
||||
case UIStyleColorProperty.FontColor: return fontColor;
|
||||
case UIStyleColorProperty.FontOutlineColor: return outlineColor;
|
||||
case UIStyleColorProperty.FontShadowColor: return shadowColor;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -132,8 +260,367 @@ namespace Rokojori
|
|||
return GetReferenceableNumberProperty( style, property );
|
||||
}
|
||||
|
||||
public static UIColor GetReferenceableColorProperty( UIStylePropertyContainer container, UIStyleColorProperty property )
|
||||
{
|
||||
if ( container == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ownProperty = container.GetUIStyleColorProperty( property );
|
||||
|
||||
if ( ownProperty != null )
|
||||
{
|
||||
return ownProperty;
|
||||
}
|
||||
|
||||
var style = container.GetUIStyleParent();
|
||||
|
||||
return GetReferenceableColorProperty( style, property );
|
||||
}
|
||||
|
||||
public static UINumberTransition GetTransition( UIStylePropertyContainer container, UIStyleNumberProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
{
|
||||
case UIStyleNumberProperty.FontSize:
|
||||
case UIStyleNumberProperty.FontOutlineSize:
|
||||
case UIStyleNumberProperty.FontShadowSize:
|
||||
case UIStyleNumberProperty.FontShadowOffsetX:
|
||||
case UIStyleNumberProperty.FontShadowOffsetY:
|
||||
{
|
||||
return _GetTransition( true, container, property );
|
||||
}
|
||||
}
|
||||
|
||||
return _GetTransition( false, container, property );
|
||||
|
||||
}
|
||||
|
||||
static UINumberTransition _GetTransition( bool inheritable, UIStylePropertyContainer container, UIStyleNumberProperty property )
|
||||
{
|
||||
var transitions = container.GetNumberTransitions();
|
||||
|
||||
var index = transitions == null ? -1 : Arrays.FindIndex( transitions, t => t != null && t.property == property );
|
||||
|
||||
if ( index != -1 )
|
||||
{
|
||||
return transitions[ index ];
|
||||
}
|
||||
|
||||
var styleParent = container.GetUIStyleParent();
|
||||
|
||||
if ( styleParent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var styleParentTransition = _GetTransition( false, styleParent, property );
|
||||
|
||||
if ( styleParentTransition != null )
|
||||
{
|
||||
return styleParentTransition;
|
||||
}
|
||||
|
||||
if ( ! ( container is Control ) || ! inheritable )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var control = container as Control;
|
||||
UINumberTransition parentTransition = null;
|
||||
|
||||
NodesWalker.Get().GetInParents( control,
|
||||
it =>
|
||||
{
|
||||
if ( ! ( it is UIStylePropertyContainer ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var container = (UIStylePropertyContainer) it;
|
||||
parentTransition = _GetTransition( true, container, property );
|
||||
|
||||
return parentTransition != null;
|
||||
}
|
||||
);
|
||||
|
||||
return parentTransition;
|
||||
|
||||
}
|
||||
|
||||
public static TransitionSettingsAll GetTransitionSettingsAll( UIStylePropertyContainer container )
|
||||
{
|
||||
var settings = container.GetTransitionSettingsAll();
|
||||
|
||||
if ( settings != null )
|
||||
{
|
||||
return settings;
|
||||
}
|
||||
|
||||
var styleParent = container.GetUIStyleParent();
|
||||
|
||||
if ( styleParent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetTransitionSettingsAll( styleParent );
|
||||
}
|
||||
|
||||
|
||||
/*public static TransitionSettings GetTransitionSettings( UIStylePropertyContainer container, FloatPropertyName floatProperty )
|
||||
{
|
||||
var transition = GetTransition( container, floatProperty );
|
||||
|
||||
if ( transition != null && transition.settings != null )
|
||||
{
|
||||
return transition.settings;
|
||||
}
|
||||
|
||||
var containerSettings = container.GetTransitionSettingsAll();
|
||||
|
||||
if ( containerSettings != null )
|
||||
{
|
||||
return containerSettings;
|
||||
}
|
||||
|
||||
var styleParent = container.GetUIStyleParent();
|
||||
|
||||
if ( styleParent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetTransitionSettings( styleParent, floatProperty );
|
||||
}
|
||||
*/
|
||||
public static TransitionSettings GetTransitionSettings( UIStylePropertyContainer container, UIStyleColorProperty colorProperty )
|
||||
{
|
||||
var transition = GetTransition( container, colorProperty );
|
||||
|
||||
if ( transition != null && transition.settings != null )
|
||||
{
|
||||
return transition.settings;
|
||||
}
|
||||
|
||||
var containerSettings = container.GetTransitionSettingsAll();
|
||||
|
||||
if ( containerSettings != null )
|
||||
{
|
||||
return containerSettings;
|
||||
}
|
||||
|
||||
var styleParent = container.GetUIStyleParent();
|
||||
|
||||
if ( styleParent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetTransitionSettings( styleParent, colorProperty );
|
||||
}
|
||||
|
||||
public static TransitionSettings GetTransitionSettings( UIStylePropertyContainer container, UIStyleNumberProperty numberProperty )
|
||||
{
|
||||
var transition = GetTransition( container, numberProperty );
|
||||
|
||||
if ( transition != null && transition.settings != null )
|
||||
{
|
||||
return transition.settings;
|
||||
}
|
||||
|
||||
var containerSettings = container.GetTransitionSettingsAll();
|
||||
|
||||
if ( containerSettings != null )
|
||||
{
|
||||
return containerSettings;
|
||||
}
|
||||
|
||||
var styleParent = container.GetUIStyleParent();
|
||||
|
||||
if ( styleParent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return GetTransitionSettings( styleParent, numberProperty );
|
||||
}
|
||||
|
||||
public static UIColorTransition GetTransition( UIStylePropertyContainer container, UIStyleColorProperty property )
|
||||
{
|
||||
switch ( property )
|
||||
{
|
||||
case UIStyleColorProperty.FontColor:
|
||||
case UIStyleColorProperty.FontOutlineColor:
|
||||
case UIStyleColorProperty.FontShadowColor:
|
||||
{
|
||||
return _GetTransition( true, container, property );
|
||||
}
|
||||
}
|
||||
|
||||
return _GetTransition( false, container, property );
|
||||
|
||||
}
|
||||
|
||||
static UIColorTransition _GetTransition( bool inheritable, UIStylePropertyContainer container, UIStyleColorProperty property )
|
||||
{
|
||||
var transitions = container.GetColorTransitions();
|
||||
|
||||
var index = transitions == null ? -1 : Arrays.FindIndex( transitions, t => t != null && t.property == property );
|
||||
|
||||
if ( index != -1 )
|
||||
{
|
||||
return transitions[ index ];
|
||||
}
|
||||
|
||||
var styleParent = container.GetUIStyleParent();
|
||||
|
||||
if ( styleParent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var styleParentTransition = _GetTransition( false, styleParent, property );
|
||||
|
||||
if ( styleParentTransition != null )
|
||||
{
|
||||
return styleParentTransition;
|
||||
}
|
||||
|
||||
if ( ! ( container is Control ) || ! inheritable )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var control = container as Control;
|
||||
UIColorTransition parentTransition = null;
|
||||
|
||||
NodesWalker.Get().GetInParents( control,
|
||||
it =>
|
||||
{
|
||||
if ( ! ( it is UIStylePropertyContainer ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var container = (UIStylePropertyContainer) it;
|
||||
parentTransition = _GetTransition( true, container, property );
|
||||
|
||||
return parentTransition != null;
|
||||
}
|
||||
);
|
||||
|
||||
return parentTransition;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static UINumber GetInheritableNumberProperty( UIStylePropertyContainer container, UIStyleNumberProperty property )
|
||||
{
|
||||
if ( container == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ownProperty = container.GetUIStyleNumberProperty( property );
|
||||
|
||||
if ( ownProperty != null )
|
||||
{
|
||||
return ownProperty;
|
||||
}
|
||||
|
||||
var parentStyle = container.GetUIStyleParent();
|
||||
var parentStyleProperty = GetReferenceableNumberProperty( parentStyle, property );
|
||||
|
||||
if ( parentStyleProperty != null )
|
||||
{
|
||||
return parentStyleProperty;
|
||||
}
|
||||
|
||||
if ( ! ( container is Control ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var control = container as Control;
|
||||
UINumber parentNumber = null;
|
||||
|
||||
NodesWalker.Get().GetInParents( control,
|
||||
it =>
|
||||
{
|
||||
if ( ! ( it is UIStylePropertyContainer ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var container = (UIStylePropertyContainer) it;
|
||||
parentNumber = GetReferenceableNumberProperty( container, property );
|
||||
|
||||
return parentNumber != null;
|
||||
}
|
||||
);
|
||||
|
||||
return parentNumber;
|
||||
|
||||
}
|
||||
|
||||
public static UIColor GetInheritableColorProperty( UIStylePropertyContainer container, UIStyleColorProperty property )
|
||||
{
|
||||
if ( container == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var ownProperty = container.GetUIStyleColorProperty( property );
|
||||
|
||||
if ( ownProperty != null )
|
||||
{
|
||||
return ownProperty;
|
||||
}
|
||||
|
||||
var parentStyle = container.GetUIStyleParent();
|
||||
var parentStyleProperty = GetReferenceableColorProperty( parentStyle, property );
|
||||
|
||||
if ( parentStyleProperty != null )
|
||||
{
|
||||
return parentStyleProperty;
|
||||
}
|
||||
|
||||
if ( ! ( container is Control ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var control = container as Control;
|
||||
UIColor parentColor = null;
|
||||
|
||||
NodesWalker.Get().GetInParents( control,
|
||||
it =>
|
||||
{
|
||||
if ( ! ( it is UIStylePropertyContainer ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var container = (UIStylePropertyContainer) it;
|
||||
parentColor = GetReferenceableColorProperty( container, property );
|
||||
|
||||
return parentColor != null;
|
||||
}
|
||||
);
|
||||
|
||||
return parentColor;
|
||||
|
||||
}
|
||||
|
||||
public static UIPosition Position( UIStylePropertyContainer container )
|
||||
{
|
||||
if ( container == null )
|
||||
{
|
||||
return UIPosition.___;
|
||||
}
|
||||
|
||||
var ownProperty = container.GetUIPosition();
|
||||
|
||||
if ( ownProperty != UIPosition.___ )
|
||||
|
@ -141,102 +628,94 @@ namespace Rokojori
|
|||
return ownProperty;
|
||||
}
|
||||
|
||||
return container.GetUIPosition();
|
||||
var parent = container.GetUIStyleParent();
|
||||
|
||||
if ( parent == null )
|
||||
{
|
||||
return UIPosition.___;
|
||||
}
|
||||
|
||||
return parent.GetUIPosition();
|
||||
}
|
||||
|
||||
public static UINumber Width( UIStylePropertyContainer container )
|
||||
public static UILayout Layout( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Width );
|
||||
if ( container == null )
|
||||
{
|
||||
return UILayout.___;
|
||||
}
|
||||
|
||||
var ownProperty = container.GetUILayout();
|
||||
|
||||
if ( ownProperty != UILayout.___ )
|
||||
{
|
||||
return ownProperty;
|
||||
}
|
||||
|
||||
var parent = container.GetUIStyleParent();
|
||||
|
||||
if ( parent == null )
|
||||
{
|
||||
return UILayout.___;
|
||||
}
|
||||
|
||||
return parent.GetUILayout();
|
||||
}
|
||||
|
||||
public static UINumber Height( UIStylePropertyContainer container )
|
||||
public static UILineWrap LineWrap( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Height );
|
||||
if ( container == null )
|
||||
{
|
||||
return UILineWrap.___;
|
||||
}
|
||||
|
||||
var ownProperty = container.GetUILineWrap();
|
||||
|
||||
if ( ownProperty != UILineWrap.___ )
|
||||
{
|
||||
return ownProperty;
|
||||
}
|
||||
|
||||
var parent = container.GetUIStyleParent();
|
||||
|
||||
if ( parent == null )
|
||||
{
|
||||
return UILineWrap.___;
|
||||
}
|
||||
|
||||
return parent.GetUILineWrap();
|
||||
}
|
||||
|
||||
public static UINumber Left( UIStylePropertyContainer container )
|
||||
public static UINumber GetUINumberProperty( UIStylePropertyContainer container, UIStyleNumberProperty property )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Left );
|
||||
switch ( property )
|
||||
{
|
||||
case UIStyleNumberProperty.FontSize:
|
||||
case UIStyleNumberProperty.FontOutlineSize:
|
||||
case UIStyleNumberProperty.FontShadowSize:
|
||||
case UIStyleNumberProperty.FontShadowOffsetX:
|
||||
case UIStyleNumberProperty.FontShadowOffsetY:
|
||||
{
|
||||
return GetInheritableNumberProperty( container, property );
|
||||
}
|
||||
}
|
||||
|
||||
return GetReferenceableNumberProperty( container, property );
|
||||
}
|
||||
|
||||
public static UINumber Right( UIStylePropertyContainer container )
|
||||
public static UIColor GetUIColorProperty( UIStylePropertyContainer container, UIStyleColorProperty property )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Right );
|
||||
}
|
||||
switch ( property )
|
||||
{
|
||||
case UIStyleColorProperty.FontColor:
|
||||
case UIStyleColorProperty.FontOutlineColor:
|
||||
case UIStyleColorProperty.FontShadowColor:
|
||||
{
|
||||
return GetInheritableColorProperty( container, property );
|
||||
}
|
||||
}
|
||||
|
||||
public static UINumber Top( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Top );
|
||||
}
|
||||
|
||||
public static UINumber Bottom( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Bottom );
|
||||
}
|
||||
|
||||
public static UINumber Margin( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Margin );
|
||||
}
|
||||
|
||||
public static UINumber MarginLeft( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginLeft );
|
||||
}
|
||||
|
||||
public static UINumber MarginRight( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginRight );
|
||||
}
|
||||
|
||||
public static UINumber MarginTop( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginTop );
|
||||
}
|
||||
|
||||
public static UINumber MarginBottom( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginBottom );
|
||||
}
|
||||
|
||||
public static UINumber PivotX( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.PivotX );
|
||||
}
|
||||
|
||||
public static UINumber PivotY( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.PivotY );
|
||||
}
|
||||
|
||||
public static UINumber Rotation( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Rotation );
|
||||
}
|
||||
|
||||
public static UINumber Scale( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Scale );
|
||||
}
|
||||
|
||||
public static UINumber ScaleX( UIStylePropertyContainer container )
|
||||
{
|
||||
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.ScaleX );
|
||||
}
|
||||
|
||||
public static UINumber ScaleY( UIStylePropertyContainer container )
|
||||
{
|
||||
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 );
|
||||
return GetReferenceableColorProperty( container, property );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ namespace Rokojori
|
|||
|
||||
ElementSpacing,
|
||||
LineSpacing,
|
||||
HorizontalAlignment,
|
||||
VerticalAlignment,
|
||||
VerticalPlacement,
|
||||
|
||||
Margin,
|
||||
MarginLeft,
|
||||
|
@ -34,7 +37,9 @@ namespace Rokojori
|
|||
|
||||
FontSize,
|
||||
FontOutlineSize,
|
||||
FontShadowSize
|
||||
FontShadowSize,
|
||||
FontShadowOffsetX,
|
||||
FontShadowOffsetY
|
||||
}
|
||||
|
||||
public enum UIStyleColorProperty
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -9,6 +10,23 @@ namespace Rokojori
|
|||
UIStyle GetUIStyleParent();
|
||||
|
||||
UIPosition GetUIPosition();
|
||||
UILayout GetUILayout();
|
||||
UILineWrap GetUILineWrap();
|
||||
|
||||
UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property );
|
||||
UIColor GetUIStyleColorProperty( UIStyleColorProperty property );
|
||||
|
||||
ShaderUIColor[] GetShaderUIColors();
|
||||
List<ActiveStyleTransition<UIColor,ColorPropertyName>> GetActiveShaderUIColorTransitions();
|
||||
|
||||
ShaderUINumber[] GetShaderUINumbers();
|
||||
List<ActiveStyleTransition<UINumber,FloatPropertyName>> GetActiveShaderUINumberTransitions();
|
||||
|
||||
TransitionSettingsAll GetTransitionSettingsAll();
|
||||
UINumberTransition[] GetNumberTransitions();
|
||||
List<ActiveStyleTransition<UINumber,UIStyleNumberProperty>> GetActiveUINumberTransitions();
|
||||
|
||||
UIColorTransition[] GetColorTransitions();
|
||||
List<ActiveStyleTransition<UIColor,UIStyleColorProperty>> GetActiveUIColorTransitions();
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Rokojori
|
|||
{
|
||||
public static bool CanPosition( Control control )
|
||||
{
|
||||
if ( control is UIRegion || control is UIImage || control is UIText )
|
||||
if ( control is UIRegion || control is UIImage || control is UIBorderImage || control is UIText )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
public class ActiveStyleTransition<V,P>
|
||||
{
|
||||
public V value;
|
||||
public P propertyType;
|
||||
public RJTimeLine timeLine;
|
||||
public float start;
|
||||
public float end;
|
||||
public Curve curve;
|
||||
public bool transitioning;
|
||||
|
||||
public static O ProcessTransition<O>(
|
||||
UIStylePropertyContainer container, O computedValue,
|
||||
List<ActiveStyleTransition<V,P>> activeTransitions, V activeValue, P property,
|
||||
Func<TransitionSettingsAll> getTransitionSettings,
|
||||
Func<V,O> computeValue,
|
||||
Func<O,O,float,O> lerpValue
|
||||
)
|
||||
{
|
||||
var propertyTransition = activeTransitions.Find( t => t != null && EqualityComparer<P>.Default.Equals( t.propertyType, property ) );
|
||||
|
||||
if ( propertyTransition == null )
|
||||
{
|
||||
propertyTransition = new ActiveStyleTransition<V, P>();
|
||||
propertyTransition.propertyType = property;
|
||||
propertyTransition.value = activeValue;
|
||||
propertyTransition.transitioning = false;
|
||||
|
||||
activeTransitions.Add( propertyTransition );
|
||||
|
||||
return computedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ! EqualityComparer<V>.Default.Equals( propertyTransition.value, activeValue ) &&
|
||||
! propertyTransition.transitioning && getTransitionSettings() != null )
|
||||
{
|
||||
var transitionSettings = getTransitionSettings();
|
||||
propertyTransition.timeLine = transitionSettings.timeLine;
|
||||
propertyTransition.start = TimeLineManager.GetPosition( transitionSettings.timeLine );
|
||||
propertyTransition.end = propertyTransition.start + transitionSettings.duration;
|
||||
propertyTransition.transitioning = true;
|
||||
propertyTransition.curve = transitionSettings.curve;
|
||||
}
|
||||
}
|
||||
|
||||
if ( EqualityComparer<V>.Default.Equals( propertyTransition.value, activeValue ) )
|
||||
{
|
||||
propertyTransition.transitioning = false;
|
||||
return computedValue;
|
||||
}
|
||||
|
||||
var computedTransitionValue = computeValue( propertyTransition.value );
|
||||
|
||||
var transitionPhase = TimeLineManager.GetRangePhase( propertyTransition.timeLine, propertyTransition.start, propertyTransition.end );
|
||||
|
||||
if ( transitionPhase >= 1 )
|
||||
{
|
||||
activeTransitions.Remove( propertyTransition );
|
||||
}
|
||||
|
||||
var amount = MathX.Clamp01( transitionPhase );
|
||||
var curveAmount = amount;
|
||||
|
||||
if ( propertyTransition.curve != null )
|
||||
{
|
||||
curveAmount = propertyTransition.curve.Sample( curveAmount );
|
||||
}
|
||||
|
||||
return lerpValue( computedTransitionValue, computedValue, curveAmount );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class TransitionSettings:Resource
|
||||
{
|
||||
[Export]
|
||||
public float duration;
|
||||
|
||||
[Export]
|
||||
public Curve curve;
|
||||
|
||||
[Export]
|
||||
public RJTimeLine timeLine;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class TransitionSettingsAll:TransitionSettings
|
||||
{
|
||||
[Export]
|
||||
public bool transitionAllProperties;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class UIColorTransition : Resource
|
||||
{
|
||||
[Export]
|
||||
public UIStyleColorProperty property;
|
||||
|
||||
[Export]
|
||||
public TransitionSettings settings;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
using Godot;
|
||||
using Rokojori;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class UINumberTransition : Resource
|
||||
{
|
||||
[Export]
|
||||
public UIStyleNumberProperty property;
|
||||
|
||||
[Export]
|
||||
public TransitionSettings settings;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue