Editor preview renderers for pipe-related architecture parts. ArchPipePreview draws a pipe path ghost, node spheres and block tags; ArchBracketPreview draws a bracket volume and, when selected, a note showing hanger/run counts resolved from the plan.
namespace Sunless.Architecture;
public sealed class ArchPipePreview : IArchPreview
{
public ArchKind Kind => ArchKind.Pipe;
public void Draw( ArchPreviewContext context )
{
if ( context.Payload is not ArchPipePart run || context.Tool is null )
{
return;
}
var shape = context.Tool.Resolved( run.Id, () => ArchPipeShape.Resolve( context.Tool.Plan, run ) );
Gizmo.Draw.Color = context.Selected ? Color.Yellow : Color.Cyan.WithAlpha( 0.7f );
ArchGhost.Path( shape.Path().Select( point => point + Vector3.Up * context.Lift ).ToList(), false );
if ( !context.Selected )
{
return;
}
foreach ( var node in run.Nodes )
{
Gizmo.Draw.LineSphere( node.Position + Vector3.Up * context.Lift, MathF.Max( 3f, run.Radius ) );
}
foreach ( var block in shape.Blocks )
{
ArchGhost.Tag( shape.At( (block.From + block.To) * 0.5f ) + Vector3.Up * context.Lift,
$"over {block.Name}", Color.Orange );
}
}
}
public sealed class ArchBracketPreview : IArchPreview
{
public ArchKind Kind => ArchKind.Bracket;
public void Draw( ArchPreviewContext context )
{
if ( context.Payload is not ArchPipeBracketPart bracket || context.Tool is null )
{
return;
}
Gizmo.Draw.Color = context.Selected ? Color.Yellow : Color.Green.WithAlpha( 0.35f );
ArchGhost.Volume( bracket.Min, bracket.Max, bracket.BaseHeight + context.Lift, bracket.TopHeight + context.Lift );
if ( !context.Selected )
{
return;
}
var shape = context.Tool.Resolved( bracket.Id, () => ArchPipeBracket.Resolve( context.Tool.Plan, bracket ) );
ArchGhost.Note( new Vector3( bracket.Max.x, bracket.Max.y, bracket.TopHeight + context.Lift ),
$"{shape.Count} hangers · holds {shape.Held.Count} runs" );
}
}