using System; namespace IslaApocalypse.Tools { /// /// ⭐ THE SOUTHERN STRETCH (chat2/08, EXPLORATION) — the one deliberate relaxation of sea identity, /// confined to a FIXED feathered latitude band. /// /// ═══ THE MECHANISM (read from pass 1, chat2/08 diagnostic) ═══ /// /// Pass 1's mask is falloff = ½·ellipse + ½·squircle (+ edge noise · squircle), then the SOUTHERN /// SINKER adds 0.6 · (y − 0.75N)/(0.25N) for y > 0.75N, BEFORE the 2.5 power; the coast sits /// where rawBase − falloff^2.5 crosses sea, i.e. near falloff ≈ 0.66. Every term that grows with y /// is a function of the SOUTHWARD DISTANCE. The stretch compresses that distance inside the band: /// /// y' = yB + (y − yB) / (1 + stretch · ramp(y)) ramp = smoothstep over the feather /// /// so a cell at y takes the mask geometry of the row y' north of it — the mass reaches further /// south AND keeps the elevation profile of the rows it came from (the base noise, edge noise and /// latitude field keep the real y — texture stays, only the mask's geometry stretches). Where the /// stretched thin edge drops below sea it fragments organically. Nothing is stamped. /// /// ⚠ North of the band (y ≤ yB) the caller takes the untouched code path: bit-identical by /// construction, asserted by the oracle. The band line and feather are constants for a batch; /// TerrainGenConfig.SouthStretch is the only swept axis. /// /// The SINKER: TerrainGenConfig.StretchSinker decides whether it rides y' (pushed out with /// the geometry — held back inside the band) or the real y (keeps pulling the extended mass down /// where it always did). The chat2/08 diagnostic measured both — see the report. /// public static class SouthernStretch { /// The band's fixed latitude line, fraction of the map. Chosen by the chat2/08 diagnostic (see the report). public const float DefaultBandStartFrac = 0.70f; /// The feather width, fraction of the map. public const float DefaultBandFeatherFrac = 0.05f; /// Whether the sinker rides the stretched distance by default. Set by the chat2/08 diagnostic. public const bool DefaultStretchSinker = true; /// The smoothstep ramp across the feather: 0 at the band line, 1 a feather-width below it. public static float Ramp(float y, float bandStart, float bandFeather) { float t = Math.Clamp((y - bandStart) / bandFeather, 0f, 1f); return t * t * (3f - 2f * t); } /// The y the mask geometry sees. For y ≤ bandStart returns y unchanged. public static float StretchedY(float y, float bandStart, float bandFeather, float stretch) { if (y <= bandStart || stretch <= 0f) return y; float r = Ramp(y, bandStart, bandFeather); return bandStart + (y - bandStart) / (1f + stretch * r); } } }