Editor/Wall/ArchWallPiers.cs
using System;
using System.Collections.Generic;
using Sandbox;
namespace Sunless.Architecture;
// The ONE resolve of a wall's column line, as wall MODIFIERS: a pier, a quoin stack and an extrude zone are then
// one solid built by one emitter, and one list. The generator emits it, the band courses return over it, and the
// storey ring steps its path out over it - so a pier can never be proud to one of them and invisible to another.
public static class ArchWallPiers {
public static List<ArchWallModShape> Shapes( ArchWall wall, ArchWallJoin join, ArchKit kit, float height, float thickness, float soffit ) {
var shapes = new List<ArchWallModShape>();
var run = wall.Pilasters;
if ( run is not { Stands: true } ) {
return shapes;
}
var half = thickness * 0.5f;
// A wrap landing exactly on the neighbour's proud face is a coplanar pair; a bite inside it is hidden.
var bite = ArchLap.Bite( kit );
var reach = MathF.Max( half, half + run.Depth - bite );
var spread = half > 0.01f ? reach / half : 1f;
// OnCorners widens the run the strips lie INSIDE out to the neighbour's proud face, never centres one on it.
var from = run.OnCorners ? join.StartExtend * spread : 0f;
var to = run.OnCorners ? join.Length + join.EndExtendCut * spread : join.Length;
var foot = run.Foot - (run.Rise > 0.5f ? bite : 0f);
var climb = run.Rise > 0.5f ? foot + run.Rise : height - MathF.Max( 0f, run.Headroom );
var head = run.Rise > 0.5f ? climb : MathF.Min( climb, soffit );
if ( head - foot < 1f || to - from < 1f ) {
return shapes;
}
var strip = MathF.Min( run.Width, to - from );
var plinth = MathF.Max( 0f, run.Plinth );
var cap = MathF.Max( 0f, run.Cap );
var oversail = MathF.Max( ArchLap.Proud( kit ), MathF.Min( 3f, run.Depth * 0.35f ) );
foreach ( var centre in ArchWallSection.PilasterCentres( run, from, to ) ) {
if ( run.Course > 0.5f ) {
var backingHead = MathF.Max( head, height - bite );
Add( shapes, Backing( run, centre, strip, foot, backingHead, kit ), height, thickness, kit );
}
// Each block seats a bite INTO the one under it, or the shaft lands on the plinth's top face and the
// cap on the shaft's, which is a coplanar pair per pier.
Add( shapes, Belt( run, centre, strip, oversail, foot, foot + plinth ), height, thickness, kit );
Add( shapes, Shaft( run, centre, strip, foot + plinth - (plinth > 0.5f ? bite : 0f), head - cap ), height, thickness, kit );
Add( shapes, Belt( run, centre, strip, oversail, head - cap - (cap > 0.5f ? bite : 0f), head ), height, thickness, kit );
}
return shapes;
}
static ArchWallModPart Backing( ArchPilasterRun run, float centre, float strip, float bottom, float top, ArchKit kit ) {
var recess = MathF.Max( ArchLap.Proud( kit ), run.Joint > 0.01f ? run.Joint : run.Depth * 0.2f );
return new ArchWallModPart {
Name = "Pier",
Kind = ArchWallMod.Pilaster,
Along = centre,
Width = strip,
Base = bottom,
Height = top - bottom,
Depth = run.Course > 0.5f ? MathF.Max( ArchLap.Proud( kit ), run.Depth - recess ) : run.Depth,
Field = Field( run )
};
}
// The shaft, through the SAME block stack a quoin resolves to, so a course pitch rusticates it with no second
// emitter and an authored rise climbs past the storey head exactly as an authored modifier's does.
static ArchWallModPart Shaft( ArchPilasterRun run, float centre, float strip, float bottom, float top ) {
return new ArchWallModPart {
Name = "Pier",
Kind = run.Course > 0.5f ? ArchWallMod.Course : ArchWallMod.Pilaster,
Along = centre,
Width = strip,
Base = bottom,
Height = top - bottom,
Depth = run.Depth,
Course = run.Course,
Joint = run.Joint,
Field = Field( run )
};
}
// The plinth under a pier and the cap over it: one block oversailing the shaft it belts by the same on every side.
static ArchWallModPart Belt( ArchPilasterRun run, float centre, float strip, float oversail, float bottom, float top ) {
return new ArchWallModPart {
Name = "Pier",
Kind = ArchWallMod.Pilaster,
Along = centre,
Width = strip + oversail * 2f,
Base = bottom,
Height = top - bottom,
Depth = run.Depth + oversail,
Field = Field( run )
};
}
static ArchSurface Field( ArchPilasterRun run ) {
return run.Course > 0.5f ? ArchSurface.WallBase : ArchSurface.Pillar;
}
static void Add( List<ArchWallModShape> shapes, ArchWallModPart part, float height, float thickness, ArchKit kit ) {
if ( part.Height < 0.5f ) {
return;
}
var shape = ArchWallModShape.Resolve( part, part.Left, part.Right, height, thickness, kit );
if ( shape.Stands ) {
shapes.Add( shape );
}
}
}