summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/M6Presentation.fs
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 13:11:52 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 13:11:52 +0800
commit76a6850bb88546fc21f5f78a53fbda04e77c8b52 (patch)
tree45e492b623ef820d452201421b85a0b642d349bd /src/LivingVillage.Desktop/M6Presentation.fs
parent000a0b00384806ce85d54dfcd2646cb340a26f01 (diff)
downloadliving-village-76a6850bb88546fc21f5f78a53fbda04e77c8b52.tar.gz
feat(desktop): 确定性昼夜光照过渡与夜灯暖光
新增 lightingBlend 纯函数(黎明明 4:00-6:00、暮色 20:00-22:00 线性过渡,边界与 isNightTick 对齐),天空底色/世界 tint 按混合插值渲染,夜晚灯笼暖光晕强度=LanternGlow(纯叠加矩形、无每帧分配风险);回归测试含锚点/单调斜坡/确定性/光晕开关。
Diffstat (limited to 'src/LivingVillage.Desktop/M6Presentation.fs')
-rw-r--r--src/LivingVillage.Desktop/M6Presentation.fs45
1 files changed, 35 insertions, 10 deletions
diff --git a/src/LivingVillage.Desktop/M6Presentation.fs b/src/LivingVillage.Desktop/M6Presentation.fs
index 8e13183..ea8fd2f 100644
--- a/src/LivingVillage.Desktop/M6Presentation.fs
+++ b/src/LivingVillage.Desktop/M6Presentation.fs
@@ -11,7 +11,9 @@ type M6DayNight =
type M6RenderProfile =
{ Mode: M6DayNight
Background: Color
- WorldTint: Color }
+ WorldTint: Color
+ Blend: float32
+ LanternGlow: float32 }
module M6Presentation =
@@ -20,15 +22,38 @@ module M6Presentation =
| Day -> "白天"
| Night -> "夜晚"
- let profileAtTick (tick: int64) : M6RenderProfile =
- if Sim.isNightTick tick then
- { Mode = Night
- Background = Color(18, 25, 55)
- WorldTint = Color(118, 136, 184) }
- else
- { Mode = Day
- Background = Color(100, 160, 210)
- WorldTint = Color(255, 248, 224) }
+ /// 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