diff --git a/Runtime/Godot/Nodes.cs b/Runtime/Godot/Nodes.cs index 91359a7..7b918b8 100644 --- a/Runtime/Godot/Nodes.cs +++ b/Runtime/Godot/Nodes.cs @@ -3,12 +3,22 @@ using Godot; using System.Collections.Generic; using System; using System.Threading.Tasks; - +using System.Reflection; namespace Rokojori { public static class Nodes { + public static void CopyData( T from, T to ) where T:Node + { + var memberInfos = ReflectionHelper.GetDataMemberInfos( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ); + + var memberNames = Lists.Map( memberInfos, m => m.Name ); + + ReflectionHelper.CopyDataMembersFromTo( from, to, memberNames ); + + } + public static T Find( Node root, NodePathLocatorType type = NodePathLocatorType.DirectChildren, int parentOffset = 0 ) where T:Node { var it = root; diff --git a/Runtime/Godot/ResourceHelper.cs b/Runtime/Godot/ResourceHelper.cs index b2cb10f..8fc7c50 100644 --- a/Runtime/Godot/ResourceHelper.cs +++ b/Runtime/Godot/ResourceHelper.cs @@ -7,6 +7,7 @@ namespace Rokojori { public static void Overwrite( List overwriteProperties, T sourceResource, T targetResource ) where T:Resource { + } } } \ No newline at end of file diff --git a/Runtime/Localization/LocaleCode.cs b/Runtime/Localization/LocaleCode.cs new file mode 100644 index 0000000..3164efc --- /dev/null +++ b/Runtime/Localization/LocaleCode.cs @@ -0,0 +1,37 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + public enum LocaleCode + { + EN, + JA, + DE, + ES, + FR, + PT, + IT, + KO, + ZH, + RU, + PL, + TU, + AR, + NL, + SV, + HI, + TH, + ID, + VI, + EL, + CS, + FI, + UK, + RO, + HU + + } +} \ No newline at end of file diff --git a/Runtime/Localization/LocaleManager.cs b/Runtime/Localization/LocaleManager.cs new file mode 100644 index 0000000..0ed69df --- /dev/null +++ b/Runtime/Localization/LocaleManager.cs @@ -0,0 +1,15 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class LocaleManager:Node + { + [Export] + public LocaleCode languageLocale; + } +} \ No newline at end of file diff --git a/Runtime/Localization/LocaleText.cs b/Runtime/Localization/LocaleText.cs new file mode 100644 index 0000000..34ee63b --- /dev/null +++ b/Runtime/Localization/LocaleText.cs @@ -0,0 +1,43 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class LocaleText:LocalizedString + { + [Export(PropertyHint.MultilineText)] + public string en; + + [ExportGroup("Translations")] + [Export] + public LocaleTextEntry[] entries; + + [ExportGroup("Context")] + [Export(PropertyHint.MultilineText)] + public string context; + + + public override string GetLocalizedString( LocaleCode localeCode ) + { + if ( localeCode == LocaleCode.EN ) + { + return en; + } + + var entry = Arrays.Find( entries, e => e.code == localeCode ); + + if ( entry != null ) + { + return entry.content; + } + + return en; + + } + + } +} \ No newline at end of file diff --git a/Runtime/Localization/LocaleTextEntry.cs b/Runtime/Localization/LocaleTextEntry.cs new file mode 100644 index 0000000..4603e66 --- /dev/null +++ b/Runtime/Localization/LocaleTextEntry.cs @@ -0,0 +1,18 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class LocaleTextEntry:LocalizedString + { + [Export] + public LocaleCode code; + + [Export(PropertyHint.MultilineText)] + public string content; + } +} \ No newline at end of file diff --git a/Runtime/Localization/LocalizedString.cs b/Runtime/Localization/LocalizedString.cs new file mode 100644 index 0000000..07e9264 --- /dev/null +++ b/Runtime/Localization/LocalizedString.cs @@ -0,0 +1,18 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + [Tool] + [GlobalClass] + public partial class LocalizedString:Resource + { + public virtual string GetLocalizedString( LocaleCode localeCode ) + { + return ""; + } + + } +} \ No newline at end of file diff --git a/Runtime/Math/Math3D.cs b/Runtime/Math/Math3D.cs index 8734ca9..782ec36 100644 --- a/Runtime/Math/Math3D.cs +++ b/Runtime/Math/Math3D.cs @@ -332,6 +332,11 @@ namespace Rokojori return a.Lerp( b, lerp ); } + public static Vector3 LerpGlobalPosition( Node3D a, Node3D b, float lerp ) + { + return a.GlobalPosition.Lerp( b.GlobalPosition, lerp ); + } + public static Quaternion LookRotation( Vector3 direction, bool useModelFront = false ) { if ( direction.Normalized() == Vector3.Up ) diff --git a/Runtime/Math/MathX.cs b/Runtime/Math/MathX.cs index 08847f3..7923b19 100644 --- a/Runtime/Math/MathX.cs +++ b/Runtime/Math/MathX.cs @@ -361,6 +361,19 @@ namespace Rokojori return Mathf.Atan2( y1 - y0, x1 - x0 ); } + public static Curve ScaleCurve( Curve c, float scale ) + { + var clone = (Curve) c.Duplicate( true ); + + for ( int i = 0; i < clone.PointCount; i++ ) + { + var y = clone.GetPointPosition( i ).Y; + clone.SetPointValue( i, y * scale); + } + + return clone; + } + public static float CurveMaximum( Curve c, int numSamples = 20 ) { var max = 0f; diff --git a/Runtime/Procedural/Assets/Grass/GrassPatch.cs b/Runtime/Procedural/Assets/Grass/GrassPatch.cs index b912e6f..2c05b62 100644 --- a/Runtime/Procedural/Assets/Grass/GrassPatch.cs +++ b/Runtime/Procedural/Assets/Grass/GrassPatch.cs @@ -51,6 +51,12 @@ namespace Rokojori [Export] public Vector2 patchOffsetPosition = new Vector2( 0.5f, 0.5f ); + [Export] + public bool centerPatch = false; + + [Export] + public float centerPatchComputationHeightTreshold = 0.1f; + [ExportGroup( "Blade Triangles")] [Export( PropertyHint.Range, "1,256")] @@ -218,6 +224,28 @@ namespace Rokojori Vector3 _patchOffset = Vector3.Zero; + public int ComputeNumBlades() + { + if ( blades == 0 ) + { + if ( bladesX < bladesZ ) + { + bladesX = Mathf.Max( 1, bladesX ); + } + else + { + bladesZ = Mathf.Max( 1, bladesZ ); + } + } + + return ( bladesX + blades ) * ( blades + bladesZ ); + } + + public int ComputeNumTriangles() + { + return bladeSegments * 2 * ComputeNumBlades(); + } + public void CreatePatch() { if ( blades == 0 && bladesX == 0 && bladesZ == 0) @@ -348,7 +376,19 @@ namespace Rokojori } } + + if ( centerPatch ) + { + var f = 100000; + var h = centerPatchComputationHeightTreshold; + var box = Box3.Create( new Vector3( -f, -f, -f ), new Vector3( f, h, f ) ); + mg.CenterMesh( true, false, true, box ); + } + + X_numTriangles = mg.indices.Count / 3; + + output.Mesh = mg.GenerateMesh(); } diff --git a/Runtime/Procedural/Mesh/MeshGeometry.cs b/Runtime/Procedural/Mesh/MeshGeometry.cs index 6a765a5..9a65603 100644 --- a/Runtime/Procedural/Mesh/MeshGeometry.cs +++ b/Runtime/Procedural/Mesh/MeshGeometry.cs @@ -774,6 +774,45 @@ namespace Rokojori AddTriangle( p0, p1, p2 ); } } + + public void CenterMesh( bool onX = true, bool onY = true, bool onZ = true, Box3 centerCalcluationBox = null ) + { + var offset = new Vector3( 0, 0, 0 ); + var numPoints = 0; + + for ( int i = 0; i < vertices.Count; i++ ) + { + if ( centerCalcluationBox != null && ! centerCalcluationBox.ContainsPoint( vertices[ i ] ) ) + { + continue; + } + + offset += vertices[ i ]; + numPoints ++; + } + + offset /= numPoints; + + if ( ! onX ) + { + offset.X = 0; + } + + if ( ! onY ) + { + offset.Y = 0; + } + + if ( ! onZ ) + { + offset.Z = 0; + } + + + ApplyTranslation( - offset ); + + + } diff --git a/Runtime/Procedural/Scatter/ScatterList.cs b/Runtime/Procedural/Scatter/ScatterList.cs index 10ade5d..8002966 100644 --- a/Runtime/Procedural/Scatter/ScatterList.cs +++ b/Runtime/Procedural/Scatter/ScatterList.cs @@ -69,7 +69,7 @@ namespace Rokojori var before = output.Count ; output = s.Scatter( output, root ); - RJLog.Log( "Processed", before, "to", output.Count ); + // RJLog.Log( "Processed", before, "to", output.Count ); } ); diff --git a/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs b/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs index a9cf012..a023bc2 100644 --- a/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs +++ b/Runtime/Procedural/Scatter/Transform/RandomizeTransform.cs @@ -76,7 +76,7 @@ namespace Rokojori var uniformScaleRandom = Noise.Perlin( scalePerlin + new Vector3( 100002, -10002, 1000 ) ); p.position += positionOffset * positionRandom * positionOffsetScale; - p.rotation *= Quaternion.FromEuler( rotationOffset * rotationRandom * rotationOffsetScale ); + p.rotation *= Quaternion.FromEuler( rotationOffset * MathX.DegreesToRadians * rotationRandom * rotationOffsetScale ); diff --git a/Runtime/Random/RandomEngine.cs b/Runtime/Random/RandomEngine.cs index 988e4c3..fe2ddb8 100644 --- a/Runtime/Random/RandomEngine.cs +++ b/Runtime/Random/RandomEngine.cs @@ -36,6 +36,11 @@ namespace Rokojori return curve.Sample( Next() ); } + public int SampleInteger( Curve curve ) + { + return Mathf.RoundToInt( curve.Sample( Next() ) ); + } + public float Polar() { return this.Next() * 2f - 1f; diff --git a/Runtime/Tools/Arrays.cs b/Runtime/Tools/Arrays.cs index 3d27b19..2dc03d2 100644 --- a/Runtime/Tools/Arrays.cs +++ b/Runtime/Tools/Arrays.cs @@ -48,6 +48,13 @@ namespace Rokojori return -1; } + public static T Find( T[] values, Func predicate ) + { + var entryIndex = FindIndex( values, predicate ); + + return entryIndex == -1 ? default(T) : values[ entryIndex ]; + } + public static bool Contains ( T[] values, T other ) { return Array.IndexOf( values, other ) != -1; diff --git a/Runtime/Tools/ReflectionHelper.cs b/Runtime/Tools/ReflectionHelper.cs index 844dcdf..24fa91e 100644 --- a/Runtime/Tools/ReflectionHelper.cs +++ b/Runtime/Tools/ReflectionHelper.cs @@ -206,36 +206,70 @@ namespace Rokojori return index == -1 ? null : fields[ index ]; } - /*public static bool HasMember( object instance, string memberName ) - { - return GetFieldInfo( instance, memberName ) != null; - }*/ - public static List GetDataMemberInfos( object instance ) + { + var list = GetDataMemberInfos( instance, BindingFlags.Instance | BindingFlags.Public ); + list = Lists.Filter( list, m => IsType( m ) ); + return list; + } + + + public static bool IsType( MemberInfo mi ) + { + if ( mi is FieldInfo fi ) + { + return fi.FieldType == typeof( T ); + } + + if ( mi is PropertyInfo pi ) + { + return pi.PropertyType == typeof( T ); + } + + return false; + } + + public static List GetDataMemberInfos( object instance, BindingFlags flags ) { var list = new List(); var type = instance.GetType(); - var searchType = typeof( T ); - - var fields = type.GetFields( BindingFlags.Public | BindingFlags.Instance ); + var fields = type.GetFields( flags ); for ( int i = 0; i < fields.Length; i++ ) { - if ( fields[ i ].FieldType == searchType ) - { - list.Add( fields[ i ] ); - } + list.Add( fields[ i ] ); } - var properties = type.GetProperties( BindingFlags.Public | BindingFlags.Instance ); + var properties = type.GetProperties( flags ); for ( int i = 0; i < properties.Length; i++ ) { - if ( properties[ i ].PropertyType == searchType ) - { - list.Add( properties[ i ] ); - } + list.Add( properties[ i ] ); + } + + return list; + } + + public static List GetDataMemberInfos( BindingFlags flags = defaultBindings ) + { + var list = new List(); + var type = typeof( T ); + + var fields = type.GetFields( flags ); + + for ( int i = 0; i < fields.Length; i++ ) + { + list.Add( fields[ i ] ); + } + + var properties = type.GetProperties( flags | BindingFlags.GetProperty | BindingFlags.SetProperty ); + + for ( int i = 0; i < properties.Length; i++ ) + { + list.Add( properties[ i ] ); + + RJLog.Log( properties[ i ].Name ); } return list;