UI + Procedural Geometry

This commit is contained in:
Josef 2024-08-11 19:38:06 +02:00
parent 9a07e22b05
commit 575431f868
30 changed files with 1818 additions and 93 deletions

View File

@ -0,0 +1,89 @@
using System.Collections;
using System.Collections.Generic;
using System;
namespace Rokojori
{
public abstract class GraphWalker<N> where N:class
{
public virtual int NumConnectedFrom( N node ){ return 0;}
public virtual N GetConnectedFrom( N node, int index ){ return default(N);}
public abstract int NumConnectedTo( N node );
public abstract N GetConnectedTo( N node, int index );
public int NumConnectedAll( N node )
{
return NumConnectedTo( node ) + NumConnectedFrom( node );
}
public N GetConnected( N node, int index )
{
var fromConnections = NumConnectedFrom( node );
return index < fromConnections ? GetConnectedFrom( node, index ) : GetConnectedTo( node, index - fromConnections );
}
public bool IsConnectedTo( N source, N destination )
{
var processed = new HashSet<N>();
var toDo = new List<N>();
toDo.Add( source );
while ( toDo.Count > 0 )
{
var current = Lists.RemoveFirst( toDo );
if ( processed.Contains( current ) )
{
continue;
}
processed.Add( current );
var numConnected = NumConnectedTo( current );
for ( int i = 0; i < numConnected; i++ )
{
var connected = GetConnected( current, i );
if ( connected == destination )
{
return true;
}
if ( ! processed.Contains( connected ) )
{
toDo.Add( connected );
}
}
}
return false;
}
public bool IsDirectlyConnectedTo( N node, N other )
{
if ( node == null || other == null )
{
return false;
}
var connected = NumConnectedTo( node );
for ( int i = 0; i < connected; i++ )
{
if ( GetConnected( node, i ) == other )
{
return true;
}
}
return false;
}
}
}

View File

@ -240,7 +240,7 @@ namespace Rokojori
return NextNonChild( node );
}
public N GetParent( N node, Func<N,bool> predicate )
public N GetInParents( N node, Func<N,bool> predicate )
{
var p = Parent( node );

View File

@ -42,6 +42,13 @@ namespace Rokojori
GD.PrintRich( trace );
}
static void LogMessageWithFullTrace( string message )
{
var trace = GetFullTrace();
GD.PrintRich("\n[b]" + message + "[/b]");
GD.PrintRich( trace );
}
static void LogErrorMessage( string message )
{
var trace = GetTrace();
@ -49,6 +56,11 @@ namespace Rokojori
GD.PrintRich( trace );
}
static string GetFullTrace()
{
return ( new System.Diagnostics.StackTrace( true ) ).ToString();
}
static string GetTrace()
{
var stackTrace = new System.Diagnostics.StackTrace( true );
@ -86,6 +98,23 @@ namespace Rokojori
return "[color=gray] " + trace + "[/color]" ;
}
public static void LogWithFullTrace( params object[] objects)
{
var sb = new StringBuilder();
for ( int i = 0; i < objects.Length; i++ )
{
if ( i != 0 )
{
sb.Append( " " );
}
Stringify( objects[ i ], sb );
}
LogMessageWithFullTrace( sb.ToString() );
}
public static void Log( params object[] objects)
{
var sb = new StringBuilder();

View File

@ -0,0 +1,44 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
namespace Rokojori
{
public class Capsule3
{
public Vector3 start = Vector3.Zero;
public Vector3 end = Vector3.Zero;
public float radius = 1;
public Capsule3( Vector3 start, Vector3 end, float radius )
{
this.start = start;
this.end = end;
this.radius = radius;
}
public Capsule3 Copy()
{
return new Capsule3( start, end, radius );
}
public Vector3 center
{
get { return start.Lerp( end, 0.5f ); }
}
public Line3 centerLine
{
get { return new Line3( start, end ); }
}
public float DistanceToPoint( Vector3 p )
{
var lineDistance = centerLine.DistanceToPoint( p );
return Mathf.Max( 0, lineDistance - radius );
}
}
}

View File

@ -0,0 +1,77 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
namespace Rokojori
{
public abstract class Curve3
{
float _gradientSamplingRange = Mathf.Pow( 10f, -13f );
public abstract Vector3 SampleAt( float t );
public virtual void SampleMultiple( int numSamples, List<Vector3> output )
{
SampleMultiple( new Range( 0, 1 ), numSamples, output );
}
public virtual void SampleMultiple( Range range, int numSamples, List<Vector3> output )
{
var diff = range.length / ( numSamples - 1 ) ;
for ( var i = 0 ; i < numSamples; i++ )
{
var t = range.min + i * diff;
output.Add( SampleAt( t ) );
}
}
public virtual Vector3 GradientAt( float t )
{
return SampleAt( t + _gradientSamplingRange ) - SampleAt( t - _gradientSamplingRange );
}
public virtual float ComputeLength( int numSamples )
{
return ComputeSubLength( Range.Of_01 , numSamples );
}
public virtual float ComputeSubLength( Range range, int numSamples )
{
var diff = range.length / ( numSamples - 1 ) ;
var it = SampleAt( range.min );
var length = 0f;
for ( var i = 1 ; i < numSamples; i++ )
{
var t = range.min + i * diff;
var next = SampleAt( t );
length += ( next - it ).Length();
it = next;
}
return length;
}
public virtual int ComputeNumSamplesFor( Range range,
float minimumDistance, int minSamples = 2,
int numSamplesForLengthComputation = -1 )
{
if ( minSamples < 2 )
{ minSamples = 2; }
if ( numSamplesForLengthComputation <= 0 )
{ numSamplesForLengthComputation = minSamples * 4; }
float distance = ComputeSubLength( range, numSamplesForLengthComputation );
float numFloatingCuts = distance / minimumDistance;
int numSamples = Mathf.CeilToInt( numFloatingCuts );
return Mathf.Max( minSamples, numSamples );
}
}
}

View File

@ -0,0 +1,117 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
namespace Rokojori
{
public class Distance
{
/*
P = Point,
S = Sphere
L = Line,
C = Capsule
P S L C
P y y y y
S y y y
L y y
C y
*/
public static float Of( Vector3 a, Vector3 b )
{
return ( a - b ).Length();
}
public static float Of( Vector3 a, Sphere b )
{
return b.DistanceToPoint( a );
}
public static float Of( Sphere a, Vector3 b )
{
return Of( b, a );
}
public static float Of( Vector3 a, Line3 b )
{
return b.DistanceToPoint( a );
}
public static float Of( Line3 b, Vector3 a )
{
return Of( a, b );
}
public static float Of( Vector3 a, Capsule3 b )
{
return b.DistanceToPoint( a );
}
public static float Of( Capsule3 a, Vector3 b )
{
return Of( b, a );
}
public static float Of( Sphere a, Sphere b )
{
return a.DistanceToSphere( b );
}
public static float Of( Sphere a, Line3 b )
{
var centerDistance = Of( a.center, b );
return Mathf.Max( centerDistance - a.radius, 0 );
}
public static float Of( Line3 a, Sphere b )
{
return Of( b, a );
}
public static float Of( Sphere a, Capsule3 b )
{
var centerDistance = Of( a.center, b );
return Mathf.Max( centerDistance - a.radius, 0 );
}
public static float Of( Capsule3 a, Sphere b )
{
return Of( b, a );
}
public static float Of( Line3 a, Line3 b )
{
return a.DistanceToLine( b );
}
public static float Of( Line3 a, Capsule3 b )
{
var lineDistance = Of( a, b.centerLine );
return Mathf.Max( 0, lineDistance - b.radius );
}
public static float Of( Capsule3 a, Line3 b )
{
return Of( b, a );
}
public static float Of( Capsule3 a, Capsule3 b )
{
var lineDistance = Of( a.centerLine, b.centerLine );
return Mathf.Max( 0, lineDistance - ( a.radius + b.radius ) );
}
}
}

View File

@ -0,0 +1,249 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
namespace Rokojori
{
public class SubdivisionData
{
public Vector3 point;
public bool isCorner;
public Vector3 direction;
public SubdivisionData( Vector3 p, Vector3 d, bool corner = false )
{
point = p;
direction = d;
isCorner = corner;
}
}
public class LerpCurveClosestToPointResult
{
public float parameter;
public float distance;
public Vector3 point;
}
public class LerpCurve3:Curve3
{
List<Vector3> list;
public LerpCurve3( List<Vector3> list )
{
this.list = list;
if ( list.Count == 0 )
{
RJLog.Log( "LERP CURVE WITH EMPTY LIST" );
}
}
public override float ComputeLength( int numSamples )
{
var length = 0f;
var end = list.Count - 1;
for ( int i = 0; i < end; i++ )
{
var p0 = list[ i ];
var p1 = list[ i + 1 ];
length += p0.DistanceTo( p1 );
}
return length;
}
public float UndistortParameter( float parameter )
{
var completeLength = ComputeLength( 0 );
var end = list.Count - 1;
var normalizer = 1f / ( list.Count - 1 );
var length = 0f;
for ( int i = 0; i < end; i++ )
{
var p0 = list[ i ];
var p1 = list[ i + 1 ];
var t0 = i * normalizer;
var t1 = ( i + 1 ) * normalizer;
var distance = p0.DistanceTo( p1 );
if ( t0 <= parameter && parameter <= t1 )
{
length += distance * ( parameter - t0 );
return length / completeLength;
}
length += distance;
}
return 1;
}
public List<SubdivisionData> Subdivide( float distance, bool close )
{
var output = new List<SubdivisionData>();
var num = list.Count - 1;
if ( close )
{
num ++;
}
for ( var i = 0; i < num; i++ )
{
var start = list[ i ];
var end = list[ i == list.Count ? 0 : i + 1 ];
var dir = ( end - start );
var length = dir.Length();
var samples = Mathf.CeilToInt( length / distance );
output.Add( new SubdivisionData( start, dir, true ) );
for ( int j = 1; j < samples; j++ )
{
var samplePoint = j / (float) samples;
var point = start.Lerp( end, samplePoint );
output.Add( new SubdivisionData( point, dir ) );
}
}
if ( ! close )
{
var start = list[ list.Count - 2];
var end = list[ list.Count - 1];
var dir = ( end - start );
output.Add( new SubdivisionData( end, dir, true ) );
}
var dirCount = close ? output.Count : ( output.Count - 1 );
for ( int i = 0; i < dirCount; i++ )
{
var next = i == output.Count ? 0 : i + 1;
output[ i ].direction = output[ next ].point - output[ i ].point;
}
return output;
}
public override Vector3 SampleAt( float t )
{
if ( t < 0 )
{
return list[ 0 ];
}
if ( t >= 1 )
{
return list[ list.Count - 1 ];
}
if ( list.Count == 1 )
{
return list[ 0 ];
}
var listIndex = t * ( list.Count - 1 );
var flooredIndex = (int) Mathf.Floor( listIndex );
var lerpAmount = listIndex - flooredIndex;
if ( flooredIndex < 0 || ( flooredIndex >= list.Count - 1 ) )
{
RJLog.Log( "Out of range index:",flooredIndex, " t:", t, " listIndex", listIndex, "Count:", list.Count );
}
var lower = list[ flooredIndex ];
var upper = list[ flooredIndex + 1 ];
return Math3D.LerpUnclamped( lower, upper, lerpAmount );
}
public LerpCurve3 FromRange( Curve3 curve, Range range, int numSamples )
{
var points = new List<Vector3>();
curve.SampleMultiple( range, numSamples, points );
return new LerpCurve3( points );
}
public LerpCurve3 From( Curve3 curve, int numSamples )
{
return FromRange( curve, Range.Of_01, numSamples );
}
public static LerpCurve3 FromPoints( Vector3 first, Vector3 second, params Vector3[] others )
{
var points = new List<Vector3>();
points.Add( first );
points.Add( second );
points.AddRange( others );
return new LerpCurve3( points );
}
Line3 line;
public void GetClosest( Vector3 point, LerpCurveClosestToPointResult result )
{
var closestDistance = float.MaxValue;
Vector3 closestPoint = Vector3.Zero;
var closestParameter = 0f;
if ( line == null )
{
line = new Line3( Vector3.Zero, Vector3.Zero );
}
var end = list.Count - 1;
var parameterNormalizer = 1f / ( list.Count - 1f );
for ( int i = 0; i < end; i++ )
{
line.start = list[ i ];
line.end = list[ i + 1 ];
var currentParameter = line.ClostestParameterToPoint( point );
var currentClosestPoint = line.GetPointAtParameter( currentParameter );
var currentDistance = ( point - currentClosestPoint ).LengthSquared();
if ( currentDistance < closestDistance )
{
closestDistance = currentDistance;
closestPoint = currentClosestPoint;
closestParameter = ( currentParameter + i ) * parameterNormalizer;
}
}
result.distance = Mathf.Sqrt( closestDistance );
result.point = closestPoint;
result.parameter = closestParameter;
}
}
}

View File

@ -0,0 +1,198 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
namespace Rokojori
{
public class Line3:Curve3
{
public Vector3 start = Vector3.Zero;
public Vector3 end = Vector3.Zero;
public Line3( Vector3 start, Vector3 end )
{
this.start = start;
this.end = end;
}
public override Vector3 SampleAt( float t )
{
return start.Lerp( end, t );
}
public Line3 Copy( )
{
return new Line3( start, end );
}
public Vector3 direction { get { return end - start; } }
public float length { get { return direction.Length(); } }
public Vector3 GetPointAtParameter( float t )
{
return start + direction * t;
}
public Vector3 center{ get { return ( start + end ) * 0.5f; } }
public Line3 ScaleFromCenter( float scale )
{
var lineCenter = center;
var halfDirection = direction * ( 0.5f * scale );
var scaledStart = lineCenter - halfDirection;
var scaledEnd = lineCenter + halfDirection;
return new Line3( scaledStart, scaledEnd );
}
public Line3 ChangeLengthFromCenter( float lengthChange )
{
var lineCenter = center;
var halfDirection = direction * 0.5f;
var length = halfDirection.Length();
length += lengthChange * 0.5f;
halfDirection = halfDirection.Normalized() * length;
var scaledStart = lineCenter - halfDirection;
var scaledEnd = lineCenter + halfDirection;
return new Line3( scaledStart, scaledEnd );
}
public Line3 SetLengthFromCenter( float length )
{
var lineCenter = center;
var halfDirection = direction.Normalized() * ( length * 0.5f );
var scaledStart = lineCenter - halfDirection;
var scaledEnd = lineCenter + halfDirection;
return new Line3( scaledStart, scaledEnd );
}
public Vector3 ClosestPointToPoint( Vector3 point )
{
var parameter = MathX.Clamp01( ClostestParameterToPoint( point ) );
return GetPointAtParameter( parameter );
}
public float ClostestParameterToPoint( Vector3 point )
{
var startP = point - start;
var startEnd = end - start;
var startEnd2 = startEnd.Dot( startEnd );
var startEnd_startP = startEnd.Dot( startP );
if ( startEnd2 == 0 )
{
return 0;
}
var t = startEnd_startP / startEnd2;
return t;
}
public float DistanceToPoint( Vector3 point )
{
return ( point - ClosestPointToPoint( point ) ).Length();
}
public float DistanceToLine( Line3 s )
{
var points = ClosestPointsToLine( s );
return ( points[ 1 ] - points[ 0 ] ).Length();
}
public Vector3[] ClosestPointsToLine( Line3 s )
{
var parameters = ClosestParametersToLine( s );
var x = this.GetPointAtParameter( parameters.X );
var y = s.GetPointAtParameter( parameters.Y );
return new Vector3[]{ x, y };
}
public Vector2 ClosestParametersToLine( Line3 s )
{
float epsilon = 0.00000001f;
var u = this.direction;
var v = s.direction;
var w = start - s.start;
var a = u.Dot( u );
var b = u.Dot( v );
var c = v.Dot( v );
var d = u.Dot( w );
var e = v.Dot( w );
var DD = a * c - b * b;
var sc = 0f;
var sN = 0f;
var sD = 0f;
var tc = 0f;
var tN = 0f;
var tD = 0f;
sD = DD;
tD = DD;
if ( DD < epsilon )
{
sN = 0.0f;
sD = 1.0f;
tN = e;
tD = c;
}
else
{
sN = b * e - c * d ;
tN = a * e - b * d ;
if ( sN < 0.0f )
{
sN = 0.0f;
tN = e;
tD = c;
}
else if ( sN > sD )
{
sN = sD;
tN = e + b;
tD = c;
}
}
if ( tN < 0f || tN > tD )
{
var tN_bigger_tD = tN >= 0f && tN > tD;
tN = tN_bigger_tD ? tD : 0f;
var inbetween = tN_bigger_tD ? ( -d + b ) : ( -d );
var isSmaller = inbetween < 0;
var isBigger = inbetween > a;
sN = isSmaller ? 0f : isBigger ? sD : inbetween;
sD = ! isSmaller && ! isBigger ? a : sD;
}
sc = Mathf.Abs( sN ) < epsilon ? 0f : sN / sD;
tc = Mathf.Abs( tN ) < epsilon ? 0f : tN / tD;
return new Vector2( sc, tc );
}
}
}

View File

@ -0,0 +1,53 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
namespace Rokojori
{
public class Sphere
{
public Vector3 center = Vector3.Zero;
public float radius = 1;
public Sphere( Vector3 center, float radius )
{
this.center = center;
this.radius = radius;
}
public Sphere Copy()
{
return new Sphere( center, radius );
}
public float DistanceToPoint( Vector3 point )
{
return Mathf.Max( 0, ( point - center ).Length() - radius );
}
public bool ContainsPoint( Vector3 point )
{
return DistanceToPoint( point ) <= 0;
}
public float DistanceToSphere( Sphere sphere )
{
var distance = sphere.center - center;
var radiusBoth = sphere.radius + radius;
return Mathf.Max( 0, distance.Length() - radiusBoth );
}
public bool IntersectsSphere( Sphere sphere )
{
return DistanceToSphere( sphere ) <= 0;
}
public Box3 CreateBox()
{
var offset = radius * Vector3.One;
return Box3.Create( center -offset, center + offset );
}
}
}

View File

@ -0,0 +1,96 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
namespace Rokojori
{
public enum TriangleSide
{
AB,
BC,
CA
}
public class TriangleSides
{
public static readonly TriangleSide[] ALL =
{
TriangleSide.AB,
TriangleSide.BC,
TriangleSide.CA
};
}
public class Triangle3
{
public Vector3 a;
public Vector3 b;
public Vector3 c;
public Triangle3( Vector3 a, Vector3 b, Vector3 c )
{
this.a = a;
this.b = b;
this.c = c;
}
public float perimeter
{
get
{
var sideA = ( b - a ).Length();
var sideB = ( c - b ).Length();
var sideC = ( a - c ).Length();
return sideA + sideB + sideC;
}
}
public float semiperimeter
{
get
{
return perimeter * 0.5f;
}
}
public static float ComputeTriangleArea( Vector3 a, Vector3 b, Vector3 c )
{
var sideA = ( b - a ).Length();
var sideB = ( c - b ).Length();
var sideC = ( a - c ).Length();
var perimeter = sideA + sideB + sideC;
var semiperimeter = 0.5f * perimeter;
var areaValue = Mathf.Sqrt( semiperimeter * ( semiperimeter - sideA )
* ( semiperimeter - sideB )
* ( semiperimeter - sideC )) ;
return areaValue;
}
public float area
{
get
{
return ComputeTriangleArea( a, b, c );
}
}
public Line3 GetSide( TriangleSide side )
{
switch ( side )
{
case TriangleSide.AB: return new Line3( a, b );
case TriangleSide.BC: return new Line3( b, c );
case TriangleSide.CA: return new Line3( c, a );
}
return null;
}
}
}

View File

@ -8,6 +8,16 @@ namespace Rokojori
{
public class Math3D
{
public static Vector3 LerpUnclamped( Vector3 a, Vector3 b, float amount )
{
return a + amount * ( b - a );
}
public static Vector3 LerpClamped( Vector3 a, Vector3 b, float amount )
{
return LerpUnclamped( a, b, MathX.Clamp01( amount ) );
}
public static Quaternion GetGlobalRotation( Node3D node )
{
return node.GlobalBasis.GetRotationQuaternion();

View File

@ -0,0 +1,104 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
namespace Rokojori
{
public class RationalCubicBezier
{
public static float Compute(
float t,
float p0, float p1, float p2, float p3,
float w0, float w1, float w2, float w3
)
{
var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * w0;
var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * w1;
var bp2 = 3 * ( 1 - t ) * t * t * w2;
var bp3 = t * t * t * w3;
var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
var projection = bp0 + bp1 + bp2 + bp3;
return weighted / projection;
}
public static Vector2 Compute(
float t,
Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3,
float w0, float w1, float w2, float w3
)
{
var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * w0;
var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * w1;
var bp2 = 3 * ( 1 - t ) * t * t * w2;
var bp3 = t * t * t * w3;
var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
var projection = bp0 + bp1 + bp2 + bp3;
return weighted / projection;
}
public static Vector3 Compute(
float t,
Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3,
float w0, float w1, float w2, float w3
)
{
var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * w0;
var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * w1;
var bp2 = 3 * ( 1 - t ) * t * t * w2;
var bp3 = t * t * t * w3;
var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
var projection = bp0 + bp1 + bp2 + bp3;
return weighted / projection;
}
public static Vector2 Compute( float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3 )
{
var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * p0.Z;
var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * p1.Z;
var bp2 = 3 * ( 1 - t ) * t * t * p2.Z;
var bp3 = t * t * t * p3.Z;
var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
var projection = bp0 + bp1 + bp2 + bp3;
var result = weighted / projection;
return new Vector2( result.X, result.Y );
}
public static Vector3 Compute( float t, Vector4 p0, Vector4 p1, Vector4 p2, Vector4 p3 )
{
var bp0 = ( 1 - t ) * ( 1 - t ) * ( 1 - t ) * p0.W;
var bp1 = 3 * ( 1 - t ) * ( 1 - t ) * t * p1.W;
var bp2 = 3 * ( 1 - t ) * t * t * p2.W;
var bp3 = t * t * t * p3.W;
var weighted = p0 * bp0 + p1 * bp1 + p2 * bp2 + p3 * bp3;
var projection = bp0 + bp1 + bp2 + bp3;
var result = weighted / projection;
return new Vector3( result.X, result.Y, result.Z );
}
}
}

View File

@ -0,0 +1,20 @@
Match: \.magnitude
Replace: .Length()
Match: \.normalized
Replace: .Normalized()
Match: Vector3\.(Lerp|Dot)\(\s*(\w+)\s*,\s*
Replace: $2.$1(
Match: Vector3\.Distance\(\s*(\w+)\s*,\s*
Replace: $1.DistanceTo(
Match: \.x
Replace: .X
Match: \.Y
Replace: .Y
Match: \.z
Replace: .Z

View File

@ -0,0 +1,138 @@
using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
namespace Rokojori
{
public class MeshGeometry
{
public List<Vector3> vertices;
public List<int> indices;
public List<Vector3> normals;
public List<Vector2> uvs;
public List<Vector2> uv2s;
public List<Color> colors;
public void Initialize( bool normals = true, bool uvs = true, bool colors = false, bool uvs2 = false)
{
this.vertices = new List<Vector3>();
this.indices = new List<int>();
this.normals = normals ? new List<Vector3>() : null;
this.uvs = uvs ? new List<Vector2>() : null;
this.uv2s = uvs2 ? new List<Vector2>() : null;
this.colors = colors ? new List<Color>() : null;
}
public void AddTriangle(
Vector3 va, Vector3 vb, Vector3 vc,
Vector3 na, Vector3 nb, Vector3 nc,
Vector2 uva, Vector2 uvb, Vector2 uvc
)
{
var index = vertices.Count;
Lists.Add( vertices, va, vb, vc );
Lists.Add( normals, na, nb, nc );
Lists.Add( uvs, uva, uvb, uvc );
Lists.Add( indices, index, index + 1, index + 2 );
}
public void AddQuad(
Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd,
Vector3 na, Vector3 nb, Vector3 nc, Vector3 nd,
Vector2 uva, Vector2 uvb, Vector2 uvc, Vector2 uvd
)
{
AddTriangle( va, vb, vc, na, nb, nc, uva, uvb, uvc );
AddTriangle( vc, vd, va, nc, nd, na, uvc, uvd, uva );
}
public void AddTriangle(
Vector3 va, Vector3 vb, Vector3 vc,
Vector2 uva, Vector2 uvb, Vector2 uvc
)
{
var n = Vector3.Up;
AddTriangle( va, vb, vc,
n, n, n,
uva, uvb, uvc );
}
public void AddQuad(
Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd,
Vector2 uva, Vector2 uvb, Vector2 uvc, Vector2 uvd
)
{
AddTriangle( va, vb, vc, uva, uvb, uvc );
AddTriangle( vc, vd, va, uvc, uvd, uva );
}
public void AddTriangle( Vector3 va, Vector3 vb, Vector3 vc )
{
var n = Vector3.Up;
var uv = Vector2.Zero;
AddTriangle( va, vb, vc, n, n, n, uv, uv, uv );
}
public void AddQuad( Vector3 va, Vector3 vb, Vector3 vc, Vector3 vd )
{
AddTriangle( va, vb, vc );
AddTriangle( vc, vd, va );
}
public ArrayMesh Generate( Mesh.PrimitiveType type = Mesh.PrimitiveType.Triangles, ArrayMesh arrayMesh = null )
{
if ( arrayMesh == null )
{
arrayMesh = new ArrayMesh();
}
var surfaceArray = new Godot.Collections.Array();
surfaceArray.Resize( (int) Mesh.ArrayType.Max );
if ( vertices != null )
{
surfaceArray[ (int) Mesh.ArrayType.Vertex ] = vertices.ToArray();
}
if ( normals != null )
{
surfaceArray[ (int) Mesh.ArrayType.Normal ] = normals.ToArray();
}
if ( uvs != null )
{
surfaceArray[ (int) Mesh.ArrayType.TexUV ] = uvs.ToArray();
}
if ( uv2s != null )
{
surfaceArray[ (int) Mesh.ArrayType.TexUV2 ] = uv2s.ToArray();
}
if ( colors != null )
{
surfaceArray[ (int) Mesh.ArrayType.Color ] = colors.ToArray();
}
if ( indices != null )
{
surfaceArray[ (int) Mesh.ArrayType.Index ] = indices.ToArray();
}
arrayMesh.AddSurfaceFromArrays( Mesh.PrimitiveType.Triangles, surfaceArray );
return arrayMesh;
}
}
}

View File

@ -208,6 +208,106 @@ namespace Rokojori
return list[ index ];
}
public T RemoveFrom<T>( List<T> list )
{
if ( list.Count == 0 )
{
return default ( T );
}
var index = this.IntegerExclusive( 0, list.Count );
var item = list[ index ];
list.RemoveAt( index );
return item;
}
public List<T> RemoveMutlipleFrom<T>( List<T> list, int amount )
{
if ( amount >= list.Count )
{
return list;
}
var items = new List<T>();
for ( int i = 0; i < amount; i++ )
{
var itemIndex = this.IntegerExclusive( 0, list.Count );
var item = list[ itemIndex ];
list.RemoveAt( itemIndex );
items.Add( item );
}
return items;
}
public T RemoveWeightedFrom<T>( List<T> list, List<float> weights )
{
if ( list == null || list.Count == 0 )
{
return default(T);
}
if ( list.Count == 1 )
{
return list[ 0 ];
}
var weightedSelection = RemoveMultipleWeightedFrom( list, weights, 1 );
return weightedSelection[ 0 ];
}
public List<T> RemoveMultipleWeightedFrom<T>( List<T> list, List<float> weights, int amount )
{
if ( amount >= list.Count )
{
return list;
}
var sumWeights = 0f;
weights.ForEach( w => sumWeights += w );
var selection = new List<T>();
for ( int i = 0; i < amount; i++ )
{
var number = Range( 0, sumWeights );
var index = _FindElementIndexWithWeights( weights, Range( 0, sumWeights ) );
var element = list[ index ];
var weight = weights[ index ];
list.RemoveAt( index );
sumWeights -= weight;
selection.Add( element );
}
return selection;
}
int _FindElementIndexWithWeights( List<float> weights, float value )
{
var limit = 0f;
for ( int i = 0; i < weights.Count; i++ )
{
var before = limit;
limit += weights[ i ];
if ( before <= value && value < limit )
{
return i;
}
}
return weights.Count - 1;
}
}
public abstract class SeedableRandomEngine:RandomEngine

View File

@ -0,0 +1,10 @@
vec3 localToWorld( vec3 _VERTEX, mat4 _MODEL_MATRIX )
{
return ( _MODEL_MATRIX * vec4( _VERTEX, 1.0 ) ).xyz;
}
vec3 worldToLocal( vec3 _VERTEX, mat4 _MODEL_MATRIX )
{
return ( inverse( _MODEL_MATRIX ) * vec4( _VERTEX, 1.0 ) ).xyz;
}

View File

@ -36,6 +36,28 @@ namespace Rokojori
return list.IndexOf( item ) != - 1;
}
public static T RemoveAt<T>( List<T> list, int index )
{
if ( list.Count == 0 || index < 0 || ( index > ( list.Count - 1 ) ) )
{
return default(T);
}
var first = list[ index ];
list.RemoveAt( index );
return first;
}
public static T RemoveFirst<T>( List<T> list )
{
return RemoveAt( list, 0 );
}
public static T RemoveLast<T>( List<T> list )
{
return RemoveAt( list, list.Count - 1 );
}
public static T Pop<T>( List<T> list )
{
if ( list.Count == 0 ){ return default(T); }
@ -143,6 +165,23 @@ namespace Rokojori
return copy;
}
public static List<U> FilterAndMap<T,U>( List<T> list, Func<T,int,bool> filter, Func<T,U> map)
{
var mapped = new List<U>();
for ( int i = 0; i < list.Count; i++ )
{
if ( ! filter( list[ i ], i ) )
{
continue;
}
mapped.Add( map( list[ i ] ) );
}
return mapped;
}
public static void Filter<T>( List<T> inputList, List<T> list, Func<T,int,bool> filter )
{
for ( int i = 0; i < inputList.Count; i++ )
@ -200,6 +239,24 @@ namespace Rokojori
return list;
}
public static void Add<T>( List<T> list, params T[] entries )
{
list.AddRange( entries );
}
public static void Insert<T>( List<T> list, T item, int index )
{
if ( index >= list.Count )
{
list.Add( item );
return;
}
index = index < 0 ? 0 : index;
list.Insert( index, item );
}
public static T Find<T>( List<T> list, Func<T,bool> callback )
{
for ( int i = 0; i < list.Count; i++ )

36
Runtime/Tools/Safe.cs Normal file
View File

@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using System;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Rokojori
{
public class Safe
{
static readonly int maxWhileIterations = 1000 * 1000;
public static void While( Func<bool> condition, Action action, Action onTooManyIterations = null )
{
var it = 0;
while ( it < Safe.maxWhileIterations && condition() )
{
action();
it++;
}
if ( it >= Safe.maxWhileIterations )
{
RJLog.LogWithFullTrace( "Loop with too many iterations" );
if ( onTooManyIterations != null )
{
onTooManyIterations();
}
}
}
}
}

View File

@ -67,13 +67,13 @@ namespace Rokojori
var maxWidth = 0f;
var maxHeight = 0f;
if ( UINumber.IsNullOrNone( region.width ) )
if ( UINumber.IsNullOrNone( UIStyle.Width( region ) ) )
{
lines.ForEach( l => { maxWidth = Mathf.Max( maxWidth, l.maxX ); } );
}
else
{
maxWidth = UINumber.Compute( region, region.width );
maxWidth = UINumber.Compute( region, UIStyle.Width( region ) );
}
if ( lines.Count > 0 )
@ -81,12 +81,12 @@ namespace Rokojori
maxHeight = lines[ lines.Count - 1 ].maxY;
}
var margin = UINumber.Compute( region, region.margin, 0 );
var marginLeft = margin + UINumber.Compute( region, region.marginLeft, 0 );
var marginTop = margin + UINumber.Compute( region, region.marginTop, 0 );
var margin = UINumber.Compute( region, UIStyle.Margin( region ), 0 );
var marginLeft = margin + UINumber.Compute( region, UIStyle.MarginLeft( region ), 0 );
var marginTop = margin + UINumber.Compute( region, UIStyle.MarginTop( region ), 0 );
var marginRight = margin + UINumber.Compute( region, region.marginRight, 0 );
var marginBottom = margin + UINumber.Compute( region, region.marginBottom, 0 );
var marginRight = margin + UINumber.Compute( region, UIStyle.MarginRight( region ), 0 );
var marginBottom = margin + UINumber.Compute( region, UIStyle.MarginBottom( region ), 0 );
var marginOffset = new Vector2( marginLeft, marginTop );
@ -98,46 +98,38 @@ namespace Rokojori
region.Size = new Vector2( maxWidth + horizontalMargins, maxHeight + verticalMargins );
if ( region.position == UIPosition.Parent_Anchor )
if ( UIStyle.Position( region ) == UIPosition.Parent_Anchor )
{
var p = NodesWalker.Get().Parent( region ) as Control;
if ( p != null )
{
var pWidth = UILayouting.GetWidth( p );
var pHeight = UILayouting.GetHeight( p );
var x = p.Position.X;
var y = p.Position.Y;
if ( ! UINumber.IsNullOrNone( region.left ))
{
var left = UINumber.Compute( region, region.left, 0 );
x = left;
}
else if ( ! UINumber.IsNullOrNone( region.right ) )
{
var right = UINumber.Compute( region, region.right, 0 );
x = ( pWidth - UILayouting.GetWidth( region ) ) - right;
UILayouting.SetPositionInParentAnchor( region );
}
UILayouting.SetPosition( region, new Vector2( x, y ) );
Nodes.ForEachDirectChild<Control>( region,
child =>
{
var styleContainer = child as UIStylePropertyContainer;
if ( styleContainer == null || UIStyle.Position( styleContainer ) != UIPosition.Parent_Anchor )
{
return;
}
UILayouting.UpdateChild( child );
UILayouting.SetPositionInParentAnchor( styleContainer );
}
);
}
static List<Line> CreateLines( UIRegion region )
{
var x = 0f;
var width = UINumber.Compute( region, region.width, 100000000f );
var width = UINumber.Compute( region, UIStyle.Width( region ), 100000000f );
var lines = new List<Line>();
var currentLine = new Line();
var elementSpacing = UINumber.Compute( region, region.elementSpacing, 0f );
var elementSpacing = UINumber.Compute( region, UIStyle.ElementSpacing( region ), 0f );
Nodes.ForEachDirectChild<Control>( region, c => UILayouting.UpdateChild( c ) );
@ -146,6 +138,13 @@ namespace Rokojori
child =>
{
var styleContainer = child as UIStylePropertyContainer;
if ( styleContainer != null && UIStyle.Position( styleContainer ) == UIPosition.Parent_Anchor )
{
return;
}
var cWidth = UILayouting.GetWidth( child );
var cHeight = UILayouting.GetHeight( child );
@ -193,13 +192,13 @@ namespace Rokojori
lines.ForEach( line => AdjustVerticalAlignment( region, line, verticalAlignment ) );
if ( UINumber.IsNullOrNone( region.width ) )
if ( UINumber.IsNullOrNone( UIStyle.Width( region ) ) )
{
return;
}
var horizontalAlignment = UINumber.Compute( region, region.horizontalAlignment, 0.5f, 1 );
var maxWidth = UINumber.Compute( region, region.width, 0 );
var maxWidth = UINumber.Compute( region, UIStyle.Width( region ), 0 );
lines.ForEach( line => AdjustHorizontalAlignment( region, line, horizontalAlignment, maxWidth ) );

View File

@ -40,6 +40,45 @@ namespace Rokojori
UILayouting.UpdatePivot( control );
}
public static void SetPositionInParentAnchor( UIStylePropertyContainer region )
{
var control = (Control) region;
var p = NodesWalker.Get().Parent( control ) as Control;
var pWidth = p == null ? UI.GetWindowWidth( control ) : UILayouting.GetWidth( p );
var pHeight = p == null ? UI.GetWindowHeight( control ) : UILayouting.GetHeight( p );
var x = p.Position.X;
var y = p.Position.Y;
if ( ! UINumber.IsNullOrNone( UIStyle.Left( region ) ))
{
var left = UINumber.Compute( control, UIStyle.Left( region ), 0 );
x = left;
}
else if ( ! UINumber.IsNullOrNone( UIStyle.Right( region ) ) )
{
var right = UINumber.Compute( control, UIStyle.Right( region ), 0 );
x = ( pWidth - UILayouting.GetWidth( control ) ) - right;
}
if ( ! UINumber.IsNullOrNone( UIStyle.Top( region ) ))
{
var top = UINumber.Compute( control, UIStyle.Top( region ), 0 );
y = top;
}
else if ( ! UINumber.IsNullOrNone( UIStyle.Bottom( region ) ) )
{
var bottom = UINumber.Compute( control, UIStyle.Bottom( region ), 0 );
y = ( pHeight - UILayouting.GetHeight( control ) ) - bottom;
}
UILayouting.SetPosition( control, new Vector2( x, y ) );
}
public static void UpdatePivot( Control c )
{
if ( ! ( c is UIImage || c is UIRegion || c is UIText ) )
@ -49,8 +88,8 @@ namespace Rokojori
var container = c as UIStylePropertyContainer;
var pivotX = UINumber.Compute( c, UIStyle.PivotX( container ), 0, c.Size.X );
var pivotY = UINumber.Compute( c, UIStyle.PivotY( container ), 0, c.Size.Y );
var pivotX = UINumber.Compute( c, UIStyle.PivotX( container ), 0.5f * c.Size.X, c.Size.X );
var pivotY = UINumber.Compute( c, UIStyle.PivotY( container ), 0.5f * c.Size.Y, c.Size.Y );
c.PivotOffset = new Vector2( pivotX, pivotY );

View File

@ -8,6 +8,9 @@ namespace Rokojori
[GlobalClass]
public partial class UIImage:TextureRect, UIStylePropertyContainer
{
[Export]
public UIStyle parentStyle;
[ExportCategory("Size & Margins")]
[Export]
public UINumber width;
@ -60,6 +63,16 @@ namespace Rokojori
public UINumber scaleY;
public UIStyle GetUIStyleParent()
{
return parentStyle;
}
public UIPosition GetUIPosition()
{
return position;
}
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
{
switch ( property )

View File

@ -8,7 +8,7 @@ namespace Rokojori
public partial class UIRegion : Control, UIStylePropertyContainer
{
[Export]
public UIStyle parent;
public UIStyle parentStyle;
[ExportCategory( "Layout" )]
[Export]
@ -44,6 +44,26 @@ namespace Rokojori
[Export]
public UINumber marginBottom;
[ExportCategory( "Font" )]
[Export]
public Font font;
[Export]
public UINumber fontSize;
[Export]
public UIColor fontColor;
[Export]
public UINumber outlineSize;
[Export]
public UIColor outlineColor;
[Export]
public UINumber shadowSize;
[Export]
public UIColor shadowColor;
[ExportCategory( "Position" )]
[Export]
public UIPosition position;
@ -57,6 +77,16 @@ namespace Rokojori
public UINumber bottom;
public UIStyle GetUIStyleParent()
{
return parentStyle;
}
public UIPosition GetUIPosition()
{
return position;
}
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
{
switch ( property )
@ -69,6 +99,10 @@ namespace Rokojori
case UIStyleNumberProperty.Width: return width;
case UIStyleNumberProperty.Height: return height;
case UIStyleNumberProperty.ElementSpacing: return elementSpacing;
case UIStyleNumberProperty.LineSpacing: return lineSpacing;
case UIStyleNumberProperty.Margin: return margin;
case UIStyleNumberProperty.MarginLeft: return marginLeft;

View File

@ -8,6 +8,12 @@ namespace Rokojori
[GlobalClass]
public partial class UIText:Label,UIStylePropertyContainer
{
[Export]
public UIStyle parentStyle;
[Export]
public UINumber fontSize;
[ExportCategory("Size & Margins")]
[Export]
public UINumber width;
@ -59,6 +65,15 @@ namespace Rokojori
[Export]
public UINumber scaleY;
public UIStyle GetUIStyleParent()
{
return parentStyle;
}
public UIPosition GetUIPosition()
{
return position;
}
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
{

View File

@ -0,0 +1,15 @@
using Godot;
using Rokojori;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class UIColor : Resource
{
[Export]
public Color color;
}
}

View File

@ -34,6 +34,7 @@ namespace Rokojori
return number.IsNone;
}
public static float Compute( Control control, UINumber number, float alternative = 0, float relative = 100 )
{
if ( number == null || control == null || number.IsNone )
@ -41,19 +42,9 @@ namespace Rokojori
return alternative;
}
var width = 0;
var height = 0;
var width = UI.GetWindowWidth( control );
var height = UI.GetWindowHeight( control );
if ( Engine.IsEditorHint() )
{
width = ProjectSettings.GetSetting( "display/window/size/viewport_width" ).AsInt32();
height = ProjectSettings.GetSetting( "display/window/size/viewport_height" ).AsInt32();
}
else
{
width = control.GetWindow().Size.X;
height = control.GetWindow().Size.Y;
}
return Compute( control, number, width, height, relative );
@ -75,7 +66,7 @@ namespace Rokojori
if ( _ui == null )
{
// _ui = NodesWalker.Get().GetParent( control, n => n is UI ) as UI;
_ui = NodesWalker.Get().GetInParents( control, n => n is UI ) as UI;
}
switch ( number.unit )
@ -95,6 +86,18 @@ namespace Rokojori
return number.value * height / 100f;
}
case "pw":
{
var parent = control.GetParent<Control>();
return number.value / 100f * ( parent == null ? width : parent.Size.X );
}
case "ph":
{
var parent = control.GetParent<Control>();
return number.value / 100f * ( parent == null ? height : parent.Size.Y );
}
case "px": case "":
{
return number.value;
@ -110,17 +113,25 @@ namespace Rokojori
var expressionText = number.unit == null ? "" : RegexUtility.Replace( number.unit, "%", " * relative " );
var parseResult = expression.Parse( expressionText, new string[]{ "em","vw", "vh", "px", "relative", "value" } );
var parseResult = expression.Parse( expressionText,
new string[]
{
"em","vw", "vh", "pw", "ph", "px", "relative", "value" }
);
if ( Error.Ok != parseResult )
{
return 0;
}
var parentControl = control.GetParent<Control>();
var inputs = new Godot.Collections.Array();
inputs.Add( em() );
inputs.Add( width / 100f );
inputs.Add( height / 100f );
inputs.Add( ( parentControl == null ? width : parentControl.Size.X ) / 100f );
inputs.Add( ( parentControl == null ? height : parentControl.Size.Y ) / 100f );
inputs.Add( 1 );
inputs.Add( relative / 100f );

View File

@ -6,6 +6,7 @@ namespace Rokojori
{
public enum UIPosition
{
___,
From_Layout,
Parent_Anchor
}

View File

@ -7,106 +7,236 @@ namespace Rokojori
[Tool]
[GlobalClass]
public partial class UIStyle:Resource
public partial class UIStyle:Resource, UIStylePropertyContainer
{
[Export]
public UIStyle parent;
public UIStyle parentStyle;
[ExportCategory( "Layout" )]
[Export]
public UILayout layout;
[Export]
public UILayout layoutType;
public UINumber horizontalAlignment;
[Export]
public UINumber verticalAlignment;
[ExportCategory("Width")]
[Export]
public float widthValue = 1;
public UINumber elementSpacing;
[Export]
public string widthUnit = "vw";
public UINumber lineSpacing;
[ExportCategory("Height")]
[Export]
public float heightValue = 1;
[Export]
public string heightUnit = "vw";
[ExportCategory("LineSpacing")]
[ExportCategory( "Size & Margins" )]
[Export]
public float lineSpacingValue = 1;
public UINumber width;
[Export]
public string ineSpacingtUnit = "vw";
public UINumber height;
[Export]
public UINumber margin;
[Export]
public UINumber marginLeft;
[Export]
public UINumber marginTop;
[Export]
public UINumber marginRight;
[Export]
public UINumber marginBottom;
[ExportCategory( "Font" )]
[Export]
public Font font;
[Export]
public UINumber fontSize;
[Export]
public UIColor fontColor;
[Export]
public UINumber outlineSize;
[Export]
public UIColor outlineColor;
[Export]
public UINumber shadowSize;
[Export]
public UIColor shadowColor;
[ExportCategory( "Position" )]
[Export]
public UIPosition position;
[Export]
public UINumber left;
[Export]
public UINumber top;
[Export]
public UINumber right;
[Export]
public UINumber bottom;
public UIStyle GetUIStyleParent()
{
return parentStyle;
}
public UIPosition GetUIPosition()
{
return position;
}
public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property )
{
switch ( property )
{
case UIStyleNumberProperty.Left: return left;
case UIStyleNumberProperty.Right: return right;
case UIStyleNumberProperty.Top: return top;
case UIStyleNumberProperty.Bottom: return bottom;
case UIStyleNumberProperty.ElementSpacing: return elementSpacing;
case UIStyleNumberProperty.LineSpacing: return lineSpacing;
case UIStyleNumberProperty.Width: return width;
case UIStyleNumberProperty.Height: return height;
case UIStyleNumberProperty.Margin: return margin;
case UIStyleNumberProperty.MarginLeft: return marginLeft;
case UIStyleNumberProperty.MarginRight: return marginRight;
case UIStyleNumberProperty.MarginTop: return marginTop;
case UIStyleNumberProperty.MarginBottom: return marginBottom;
}
return null;
}
public static UINumber GetReferenceableNumberProperty( UIStylePropertyContainer container, UIStyleNumberProperty property )
{
if ( container == null )
{
return null;
}
var ownProperty = container.GetUIStyleNumberProperty( property );
if ( ownProperty != null )
{
return ownProperty;
}
var style = container.GetUIStyleParent();
return GetReferenceableNumberProperty( style, property );
}
public static UIPosition Position( UIStylePropertyContainer container )
{
var ownProperty = container.GetUIPosition();
if ( ownProperty != UIPosition.___ )
{
return ownProperty;
}
return container.GetUIPosition();
}
public static UINumber Width( UIStylePropertyContainer container )
{
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Width );
}
public static UINumber Height( UIStylePropertyContainer container )
{
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Height );
}
public static UINumber Left( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Left );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Left );
}
public static UINumber Right( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Right );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Right );
}
public static UINumber Top( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Top );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Top );
}
public static UINumber Bottom( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Bottom );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Bottom );
}
public static UINumber Margin( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Margin );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Margin );
}
public static UINumber MarginLeft( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginLeft );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginLeft );
}
public static UINumber MarginRight( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginRight );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginRight );
}
public static UINumber MarginTop( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginTop );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginTop );
}
public static UINumber MarginBottom( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.MarginBottom );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.MarginBottom );
}
public static UINumber PivotX( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.PivotX );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.PivotX );
}
public static UINumber PivotY( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.PivotY );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.PivotY );
}
public static UINumber Rotation( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Rotation );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Rotation );
}
public static UINumber Scale( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.Scale );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.Scale );
}
public static UINumber ScaleX( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.ScaleX );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.ScaleX );
}
public static UINumber ScaleY( UIStylePropertyContainer container )
{
return container.GetUIStyleNumberProperty( UIStyleNumberProperty.ScaleY );
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.ScaleY );
}
public static UINumber ElementSpacing( UIStylePropertyContainer container )
{
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.ElementSpacing );
}
public static UINumber LineSpacing( UIStylePropertyContainer container )
{
return GetReferenceableNumberProperty( container, UIStyleNumberProperty.LineSpacing );
}
}

View File

@ -14,6 +14,9 @@ namespace Rokojori
Width,
Height,
ElementSpacing,
LineSpacing,
Margin,
MarginLeft,
MarginRight,
@ -27,6 +30,17 @@ namespace Rokojori
Scale,
ScaleX,
ScaleY
ScaleY,
FontSize,
FontOutlineSize,
FontShadowSize
}
public enum UIStyleColorProperty
{
FontColor,
FontOutlineColor,
FontShadowColor
}
}

View File

@ -6,6 +6,9 @@ namespace Rokojori
{
public interface UIStylePropertyContainer
{
UIStyle GetUIStyleParent();
UIPosition GetUIPosition();
UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property );
}
}

View File

@ -54,6 +54,30 @@ namespace Rokojori
}
public static float GetWindowWidth( Control control )
{
if ( Engine.IsEditorHint() )
{
return ProjectSettings.GetSetting( "display/window/size/viewport_width" ).AsInt32();
}
else
{
return control.GetWindow().Size.X;
}
}
public static float GetWindowHeight( Control control )
{
if ( Engine.IsEditorHint() )
{
return ProjectSettings.GetSetting( "display/window/size/viewport_height" ).AsInt32();
}
else
{
return control.GetWindow().Size.Y;
}
}
}
}