rj-action-library/Runtime/Procedural/Parametric/Cuboid/Cuboid.cs

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;
}
}
}