using Godot; using Rokojori; using System.Collections.Generic; namespace Rokojori { [Tool] [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Spline.svg") ] public partial class Cuboid : Node3D { [Export] public float size = 1; [Export] public float widthExtension = 0; [Export] public float heightExtension = 0; [Export] public float depthExtension = 0; [Export] public float borderSize = 0.1f; [Export] public MeshInstance3D output; [Export] public bool update = false; [Export] public bool updateAlways = false; public override void _Process( double delta ) { if ( ! ( update || updateAlways ) ) { return; } update = false; Create(); } public float X() { return size + widthExtension; } public float Y() { return size + heightExtension; } public float Z() { return size + depthExtension; } MeshGeometry mg = null; public void Create() { var maxBorderSize = ( MathX.Min( widthExtension, heightExtension, depthExtension ) + size ) / 2f; borderSize = Mathf.Clamp( borderSize, 0, maxBorderSize ); mg = new MeshGeometry(); for ( int i = 0; i < 24; i++ ) { var p = GetPointAt( i ); mg.vertices.Add( p ); if ( i < 4 ) { mg.normals.Add( Vector3.Up ); } else if ( i < 12 ) { var cornerIndex = i - 4; mg.normals.Add( GetEdgeNormal( cornerIndex ) ); } else if ( i < 20 ) { var cornerIndex = i - 12; mg.normals.Add( GetEdgeNormal( cornerIndex ) ); } else { mg.normals.Add( Vector3.Down ); } mg.uvs.Add( Vector2.Zero ); } mg.AddQuad( 0, 1, 2, 3 ); // back AddSide( 2, 1 ); // right AddSide( 7, 3 ); // left AddSide( 0, 4 ); //front AddSide( 5, 6 ); // side b,r AddSide( 3, 2 ); // side f, r AddSide( 6, 7 ); // side f, l AddSide( 4, 5 ); // side b, l AddSide( 1, 0 ); // left, back AddCorner( 0, 1, 0 ); // back, right AddCorner( 2, 3, 1 ); // left, front AddCorner( 5, 4, 2 ); // front, right AddCorner( 7, 6, 3 ); // back AddFaceSide( 0, 1, 2, 1 ); // right AddFaceSide( 1, 3, 7, 3 ); // front AddFaceSide( 3, 2, 5, 6 ); // left AddFaceSide( 2, 0, 0, 4 ); mg.AddQuad( 20, 21, 22, 23, true ); output.Mesh = mg.GenerateMesh(); } void AddSide( int a, int b ) { mg.AddQuad( te( a ), te( b ), be( a ), be( b ) ); } void AddFaceSide( int fA, int fB, int eA, int eB ) { mg.AddQuad( tf( fB ), tf( fA), te( eA ), te( eB ) ); mg.AddQuad( bf( fB ), bf( fA), be( eA ), be( eB ), true ); } void AddCorner( int eA, int eB, int f ) { mg.AddTriangle( te( eA ), te( eB ), tf( f ), true ); mg.AddTriangle( be( eA ), be( eB ), bf( f ) ); } int tf( int index ) { return index; } int te( int index ) { return index + 4; } int be( int index ) { return index + 12; } int bf( int index ) { return index + 20; } public Vector3 GetEdgeNormal( int index ) { switch ( index ) { case 1: case 2: return Vector3.Back; case 3: case 7: return Vector3.Right; case 0: case 4: return Vector3.Left; case 5: case 6: return Vector3.Forward; } return Vector3.Zero; } public Vector3 GetOffsetFor( int left, int front ) { var x = borderSize * Mathf.Sign( left ); var z = borderSize * Mathf.Sign( front ); return new Vector3( x, 0, z ); } public Vector3 GetBoundingCornerAt( int index, bool top ) { // -Z // 0 1 // *----* //-X | | +X // *----* // 2 3 // +Z var y = Y() / ( top ? 2 : -2 ); if ( 0 == index ) { return new Vector3( -X()/2, y, +Z()/2 ); } else if ( 1 == index ) { return new Vector3( +X()/2, y, +Z()/2 ); } else if ( 2 == index ) { return new Vector3( -X()/2, y, -Z()/2 ); } else if ( 3 == index ) { return new Vector3( +X()/2, y, -Z()/2 ); } return Vector3.Zero; } public Vector3 GetPointAt( int index ) { // 00-03 4 Top Face // 04-11 8 Top Edges // 12-19 8 Bottom Edges // 20-23 4 Bottom Face if ( index < 4 ) { return GetFacePoint( index, true ); } else if ( index < 12 ) { return GetEdgePoint( index - 4, true ); } else if ( index < 20 ) { return GetEdgePoint( index - 12, false ); } else if ( index < 24 ) { return GetFacePoint( index - 20, false ); } return Vector3.Zero; } Vector3 GetFacePoint( int index, bool top ) { var cornerPoint = GetBoundingCornerAt( index, top ); var offset = Vector3.Zero; if ( 0 == index ) { offset = GetOffsetFor( 1, -1 ); } else if ( 1 == index ) { offset = GetOffsetFor( -1, -1 ); } else if ( 2 == index ) { offset = GetOffsetFor( 1, 1 ); } else if ( 3 == index ) { offset = GetOffsetFor( -1, 1 ); } return cornerPoint + offset; } Vector3 GetEdgePoint( int index, bool top ) { var cornerIndex = index / 2; var cornerPoint = GetBoundingCornerAt( cornerIndex, top ); if ( top ) { cornerPoint.Y -= borderSize; } else { cornerPoint.Y += borderSize; } var offset = Vector3.Zero; if ( 0 == cornerIndex ) { offset = index == 0 ? GetOffsetFor( 0, -1 ) : GetOffsetFor( 1, 0 ); } else if ( 1 == cornerIndex ) { offset = index == 2 ? GetOffsetFor( -1, 0 ) : GetOffsetFor( 0, -1 ); } else if ( 2 == cornerIndex ) { offset = index == 4 ? GetOffsetFor( 0, 1 ) : GetOffsetFor( 1, 0 ); } else if ( 3 == cornerIndex ) { offset = index == 6 ? GetOffsetFor( -1, 0 ) : GetOffsetFor( 0, 1 ); } return cornerPoint + offset; } } }