namespace IslaApocalypse.Tools
{
///
/// The presentation dials — everything about how a heightmap is SHOWN, and nothing about how it
/// is MADE. → `Design - Rendering - Roughness Is Presentation.md`.
///
/// ⚠ Config-gated for the same reason every shaping change is: a look decision should be an A/B
/// pair, not a memory of last week's render, and a rejected look should cost a flipped default
/// rather than a reverted commit. → `Design - Tooling - Iteration and Batching.md`.
///
/// ⚠ Kept DELIBERATELY SMALL. This is a taste gate, and iteration fatigue on a subjective gate
/// is a real failure mode — a handful of variants the eye can actually judge beats a wall of
/// near-duplicates. Three named looks, chosen so each pair isolates one question.
///
public sealed class LookConfig
{
/// Short label, used in output filenames.
public string Name = "atlas";
/// Which hypsometric palette. → .
public ReliefPalette.Kind Palette = ReliefPalette.Kind.Atlas;
///
/// Vertical exaggeration for the relief normal. ⚠ A LOOK DIAL, NOT A PHYSICAL CLAIM — the
/// raw height units are not metres. See for the measured slope
/// table this was chosen from.
///
public float ZExaggeration = 75f;
/// Compass degrees clockwise from north. 315° (NW) is the cartographic standard.
public float LightAzimuth = 315f;
/// Degrees above the horizon. 45° standard; lower = longer, more dramatic shadows.
public float LightAltitude = 45f;
///
/// How much the relief moves the tint. 0 = flat hypsometric tint, no shading at all;
/// 1 = full relief. Above ~0.85 the tint starts washing out and the map reads as a
/// greyscale DEM wearing colour.
///
public float HillshadeStrength = 0.55f;
///
/// Relief multiplier BELOW sea level.
///
/// ⚠ Deliberately much weaker than on land, and the reason is the deferral: the seabed is
/// RAW — no coast shelf, no islets, both Phase-2 items — so it is steep and noisy in a way
/// the finished terrain will not be. Shading it at full strength drags the eye to the one
/// part of the map that is knowingly unfinished. Cartographic bathymetry is conventionally
/// shown flat or lightly shaded anyway, so the convention and the deferral agree.
///
public float SeaHillshadeFactor = 0.35f;
///
/// How much of the lit side is allowed to lift toward white. Highlights SCREEN rather than
/// multiply, so sunlit slopes brighten without blowing out to paper.
///
public float HighlightGain = 0.5f;
/// The colour boundary. NOT a water surface — no water is modelled (Phase 2).
public float SeaLevel = 0.15f;
///
/// The three looks offered to the taste gate. Each pair isolates one question:
/// gradient_flat ⭐ the hero — wide colour, NO relief
/// subtle_relief the same gradient with gentle relief, for comparison
/// diagnostic_relief ⚠ a DEV VIEW for spotting artifacts. Never the pretty map.
/// atlas / dusk the task-03 plates, kept reachable
///
public static LookConfig[] Variants() => new[]
{
// ⭐ THE HERO. A wide, vivid gradient rendered FLAT — no relief at all.
//
// The developer's reference maps get their look from WIDE COLOUR + subtle relief +
// COHERENT TERRAIN. We have the first; the third is Phase 2's curve and erosion. On raw
// pre-Phase-2 noise a hillshade has nothing coherent to shade, so it renders the fine
// fractal bumpiness as visual fuzz and actively HIDES the elevation the colour is
// showing. So the pretty map leads with colour and no relief, and gets its shape from
// relief later, once there is shape worth lighting.
new LookConfig
{
Name = "gradient_flat", Palette = ReliefPalette.Kind.CostaRica,
HillshadeStrength = 0f,
},
// Tasteful relief, for comparison. ⚠ Still fuzzes on raw noise — that is the terrain,
// not the setting. Comes into its own after Phase 2 carves coherent landforms.
new LookConfig
{
Name = "subtle_relief", Palette = ReliefPalette.Kind.CostaRica,
ZExaggeration = 18f, LightAzimuth = 315f, LightAltitude = 45f,
HillshadeStrength = 0.30f,
},
// ⚠⚠ A DIAGNOSTIC, NOT A PRETTY MAP. Strong exaggeration makes slope artifacts jump
// out — a centre-line crease, a stair-step, a seam. Its bumpiness is EXAGGERATED SLOPE,
// not extra terrain. Never present this as the deliverable.
new LookConfig
{
Name = "diagnostic_relief", Palette = ReliefPalette.Kind.CostaRica,
ZExaggeration = 100f, LightAzimuth = 315f, LightAltitude = 45f,
HillshadeStrength = 0.80f,
},
// The task-03 atlas plates, kept so that look is still reachable for comparison.
new LookConfig
{
Name = "atlas", Palette = ReliefPalette.Kind.Atlas,
ZExaggeration = 75f, LightAzimuth = 315f, LightAltitude = 45f,
HillshadeStrength = 0.55f,
},
new LookConfig
{
Name = "dusk", Palette = ReliefPalette.Kind.Dusk,
ZExaggeration = 100f, LightAzimuth = 300f, LightAltitude = 35f,
HillshadeStrength = 0.70f,
},
};
public override string ToString() =>
$"{Name}: palette={Palette} zex={ZExaggeration:F0} light={LightAzimuth:F0}°/{LightAltitude:F0}° " +
$"strength={HillshadeStrength:F2} sea×{SeaHillshadeFactor:F2}";
}
}