summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/SceneDetailRender.fs
blob: 2136d255697b26609256ec6234ddcef98f5ecc8c (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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
namespace LivingVillage.Desktop

open System
open Microsoft.Xna.Framework
open Microsoft.Xna.Framework.Graphics
open LivingVillage.Kernel

/// P47 场景细节渲染层:把 `SceneDetail` 的纯函数结果落成画面。
/// 反射用「光源精灵垂直镜像 + 相位微抖」,岸边芦苇/漂浮元素用既有瓦片精灵与原创点阵图集,
/// 近景屋顶用既有屋瓦精灵 + 统一方向阴影。全部只读,不改瓦片/可达性。
module SceneDetailRender =

    let private tileX (camera: Vector2) (x: int) = x * Sim.tilePixels - int camera.X
    let private tileY (camera: Vector2) (y: int) = y * Sim.tilePixels - int camera.Y

    let private drawFlipVertical
        (spriteBatch: SpriteBatch)
        (atlas: Texture2D)
        (source: Rectangle)
        (x: int)
        (y: int)
        (color: Color) =
        spriteBatch.Draw(
            atlas,
            Rectangle(x, y, Sim.tilePixels, Sim.tilePixels),
            Nullable(source),
            color,
            0.0f,
            Vector2.Zero,
            SpriteEffects.FlipVertically,
            0.0f)

    /// 河道倒影:岸上每个光源在其正下方水面格画一份垂直镜像,随 waterFrameTickAt 相位水平微抖。
    let private drawReflections (spriteBatch: SpriteBatch) (textures: VillageArt.ArtTextures) (camera: Vector2) (map: MapGen.Result) (tick: int64) =
        let source, atlas =
            match textures.Cc0TileAtlas with
            | Some cc0 -> VillageArt.cc0TileRect VillageArt.cc0TileIndexStoneLantern, cc0
            | None -> VillageArt.atlasTileRectangle 20, textures.TileAtlas
        for (x, y, alpha) in SceneDetail.reflectionStreaks map do
            let wobble = SceneDetail.reflectionWobbleAt tick x y
            let color = VillageArt.premultiply 255 214 168 alpha
            drawFlipVertical spriteBatch atlas source (tileX camera x + wobble) (tileY camera y) color

    /// 岸边芦苇加密度:用既有芦苇精灵补绘一层贴水芦苇。
    let private drawBankReeds (spriteBatch: SpriteBatch) (textures: VillageArt.ArtTextures) (camera: Vector2) (map: MapGen.Result) =
        match textures.Cc0TileAtlas with
        | Some cc0 ->
            for (x, y) in SceneDetail.bankReedTiles map do
                spriteBatch.Draw(cc0, Rectangle(tileX camera x, tileY camera y, Sim.tilePixels, Sim.tilePixels), Nullable(VillageArt.cc0TileRect VillageArt.cc0TileIndexReeds), Color.White)
        | None ->
            let source = VillageArt.atlasTileRectangle 18
            for (x, y) in SceneDetail.bankReedTiles map do
                spriteBatch.Draw(textures.TileAtlas, Rectangle(tileX camera x, tileY camera y, Sim.tilePixels, Sim.tilePixels), Nullable(source), Color.White)

    /// 漂浮元素:原创点阵鸭/叶,按 tick 慢漂移。
    let private drawFloaters (spriteBatch: SpriteBatch) (textures: VillageArt.ArtTextures) (camera: Vector2) (map: MapGen.Result) (tick: int64) =
        for (x, y, kind) in SceneDetail.floatingProps map do
            let seed = x * 31 + y * 7
            let dx, dy = SceneDetail.floatDrift tick seed
            let frame = SceneDetail.floatFrame tick seed
            let kindIndex =
                match kind with
                | SceneDetail.DuckFloat -> FloaterArt.duckIndex
                | SceneDetail.FallenLeaf -> FloaterArt.leafIndex
            let source = FloaterArt.sourceRectangle kindIndex frame
            spriteBatch.Draw(
                textures.FloaterAtlas,
                Rectangle(tileX camera x + dx + (Sim.tilePixels - FloaterArt.cellWidth) / 2, tileY camera y + dy + (Sim.tilePixels - FloaterArt.cellHeight) / 2, FloaterArt.cellWidth, FloaterArt.cellHeight),
                Nullable(source),
                Color.White)

    /// 近景楼层层错落:屏幕空间前景屋顶带,所有阴影统一投向右下(SceneDetail.shadowOffsetPx)。
    let private drawForeground (spriteBatch: SpriteBatch) (textures: VillageArt.ArtTextures) (viewportWidth: int) (viewportHeight: int) (tick: int64) =
        let ridgeSource = VillageArt.atlasTileRectangle 8
        let eaveSource = VillageArt.atlasTileRectangle 9
        let shadowColor = VillageArt.premultiply 8 12 18 120
        let dx, dy = SceneDetail.shadowOffsetPx
        for (x, y, w) in SceneDetail.foregroundRooftops viewportWidth viewportHeight tick do
            // 统一方向阴影:先把 eave 的暗色镜像平移一份到右下,再画本体。
            spriteBatch.Draw(textures.TileAtlas, Rectangle(x + dx, y + dy, w, Sim.tilePixels), Nullable(eaveSource), shadowColor)
            spriteBatch.Draw(textures.TileAtlas, Rectangle(x, y - Sim.tilePixels, w, Sim.tilePixels), Nullable(ridgeSource), Color.White)
            spriteBatch.Draw(textures.TileAtlas, Rectangle(x, y, w, Sim.tilePixels), Nullable(eaveSource), Color.White)

    /// 一次性绘制全部 P47 场景细节(倒影 → 岸边芦苇 → 漂浮元素 → 近景前景层)。
    let draw
        (spriteBatch: SpriteBatch)
        (textures: VillageArt.ArtTextures)
        (pixel: Texture2D)
        (camera: Vector2)
        (viewportWidth: int)
        (viewportHeight: int)
        (map: MapGen.Result)
        (tick: int64) =
        drawReflections spriteBatch textures camera map tick
        drawBankReeds spriteBatch textures camera map
        drawFloaters spriteBatch textures camera map tick
        drawForeground spriteBatch textures viewportWidth viewportHeight tick