namespace LivingVillage.Desktop open Microsoft.Xna.Framework open LivingVillage.Kernel open LivingVillage.Kernel.Sim type M6DayNight = | Day | Night type M6RenderProfile = { Mode: M6DayNight Background: Color WorldTint: Color Blend: float32 LanternGlow: float32 } module M6Presentation = let dayNightLabel mode : string = match mode with | Day -> "白天" | Night -> "夜晚" /// Continuous light blend: 0 = full day, 1 = full night. Ramps are deterministic /// pure functions of the simulation tick (dawn 4:00-6:00, dusk 20:00-22:00), so the /// boundaries agree with Sim.isNightTick (night >= 22:00 or < 6:00). let lightingBlend (tick: int64) : float32 = let hourTicks = Sim.ticksPerDay / 24L let hour = float32 (tick / hourTicks) let clamp01 v = if v < 0.0f then 0.0f elif v > 1.0f then 1.0f else v if hour >= 6.0f && hour < 20.0f then 0.0f elif hour >= 22.0f then 1.0f elif hour < 4.0f then 1.0f elif hour < 6.0f then clamp01 (1.0f - (hour - 4.0f) / 2.0f) else clamp01 ((hour - 20.0f) / 2.0f) let private lerp (a: int) (b: int) (blend: float32) : int = a + int (float32 (b - a) * blend) let backgroundAtBlend (blend: float32) : Color = Color(lerp 100 18 blend, lerp 160 25 blend, lerp 210 55 blend) let worldTintAtBlend (blend: float32) : Color = Color(lerp 255 118 blend, lerp 248 136 blend, lerp 224 184 blend) /// Pure day-phase lighting: deterministic tint/background plus lantern warm-glow boost. let lightingAtTick (tick: int64) : M6RenderProfile = let blend = lightingBlend tick { Mode = if blend < 0.5f then Day else Night Background = backgroundAtBlend blend Blend = blend WorldTint = worldTintAtBlend blend LanternGlow = blend } let profileAtTick (tick: int64) : M6RenderProfile = lightingAtTick tick let clockLabel (control: SimulationControl) : string = if control.Paused then "暂停" else match control.Speed with | OneX -> "1倍速" | TwoX -> "2倍速" | FiveX -> "5倍速" /// 倍速标签(语义别名,HUD 用)。 let speedLabel (control: SimulationControl) : string = clockLabel control let private hourOf (tick: int64) : int = int ((tick / (Sim.ticksPerDay / 24L)) % 24L) /// 24 小时制的模拟时钟(HH:MM),由 tick 纯函数导出。 let clockTimeLabel (tick: int64) : string = let hourTicks = Sim.ticksPerDay / 24L let hour = hourOf tick let minute = int ((tick % hourTicks) * 60L / hourTicks) sprintf "%02d:%02d" hour minute /// 时段标签:清晨/白天/黄昏/夜晚,与实际 tick 一致(纯函数)。 let timePeriodLabel (tick: int64) : string = let hour = hourOf tick if hour < 5 then "夜晚" elif hour < 8 then "清晨" elif hour < 17 then "白天" elif hour < 20 then "黄昏" else "夜晚"