338 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			338 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C#
		
	
	
	
|   | 
 | ||
|  | 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; | ||
|  |     } | ||
|  | 
 | ||
|  |   } | ||
|  | 
 | ||
|  | } |