summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/M6Presentation.fs
blob: ea8fd2f5b8da72759304d46ab98bb585cfbaf8c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
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倍速"