Editor tool code that draws an elevation/section view for architecture editing. It computes a section plane for the edited building and draws lines for panes, profiles, sweeps and a section guide, tinting pieces by role and fading non-current floors.
using System;
using System.Collections.Generic;
using System.Linq;
using Editor;
using Sandbox;
namespace Sunless.Architecture;
// Every storey is drawn, not just the live one, because that IS the section; in plan the opposite rule holds because floors lie on top of each other.
public partial class ArchTool
{
static readonly Color Faded = new( 1f, 1f, 1f, 0.22f );
void DrawSection()
{
if ( EditedBuilding() is not { } building )
{
return;
}
var cut = Section( building );
var plane = cut.Plane;
DrawSectionLine( cut );
foreach ( var piece in cut.Pieces )
{
Gizmo.Draw.Color = Tint( piece );
Gizmo.Draw.LineThickness = piece.Floor == Level ? 2f : 1f;
if ( piece.Rakes )
{
DrawProfile( plane, piece );
continue;
}
DrawPane( plane, piece );
}
Gizmo.Draw.LineThickness = 2f;
}
// The plane's trace, so the scrubbed depth is visible while it moves.
void DrawSectionLine( ArchElevationCut cut )
{
var bounds = Extent( cut.Building );
if ( bounds.Size.Length < 1f )
{
return;
}
var plane = cut.Plane;
var from = plane.Axis == ArchViewAxis.Front ? bounds.Mins.y : bounds.Mins.x;
var to = plane.Axis == ArchViewAxis.Front ? bounds.Maxs.y : bounds.Maxs.x;
Gizmo.Draw.LineThickness = 1f;
Gizmo.Draw.Color = ArchGhost.Line.WithAlpha( 0.25f );
Gizmo.Draw.Line( plane.At( from, bounds.Mins.z ), plane.At( to, bounds.Mins.z ) );
}
static void DrawPane( ArchElevationPlane plane, ArchElevationPiece piece )
{
var a = plane.At( piece.From, piece.Foot );
var b = plane.At( piece.To, piece.Foot );
var c = plane.At( piece.To, piece.Head );
var d = plane.At( piece.From, piece.Head );
Gizmo.Draw.Line( a, b );
Gizmo.Draw.Line( b, c );
Gizmo.Draw.Line( c, d );
Gizmo.Draw.Line( d, a );
// The blueprint cross that says hole, not block.
if ( piece.Role is not (ArchElevationRole.Opening or ArchElevationRole.Cut) )
{
return;
}
Gizmo.Draw.Line( a, c );
Gizmo.Draw.Line( b, d );
}
// Both traces as authored, so a pitch reads as a pitch and a wedge as a wedge - a constant thickness carried
// under the top is a deck, and drawing a ramp that way put a sloping slab where a solid triangle stands.
static void DrawProfile( ArchElevationPlane plane, ArchElevationPiece piece )
{
Sweep( plane, piece.Profile );
Sweep( plane, piece.Soffit );
foreach ( var end in new[] { 0, piece.Profile.Count - 1 } )
{
Gizmo.Draw.Line(
plane.At( piece.Soffit[end].x, piece.Soffit[end].y ),
plane.At( piece.Profile[end].x, piece.Profile[end].y ) );
}
}
static void Sweep( ArchElevationPlane plane, IReadOnlyList<Vector2> samples )
{
for ( var index = 0; index < samples.Count - 1; index++ )
{
Gizmo.Draw.Line(
plane.At( samples[index].x, samples[index].y ),
plane.At( samples[index + 1].x, samples[index + 1].y ) );
}
}
Color Tint( ArchElevationPiece piece )
{
if ( Picked?.Targets( piece.Item ) == true )
{
return Color.Yellow;
}
if ( piece.Floor != Level )
{
return Faded;
}
return piece.Role switch
{
ArchElevationRole.Wall => Color.Cyan,
ArchElevationRole.Opening => Color.Green,
ArchElevationRole.Floor => ArchGhost.Line.WithAlpha( 0.7f ),
ArchElevationRole.Platform => Color.Magenta.WithAlpha( 0.7f ),
ArchElevationRole.Cut => Color.Red.WithAlpha( 0.8f ),
ArchElevationRole.Roof => Color.Orange.WithAlpha( 0.8f ),
_ => Color.White
};
}
}