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
98
99
100
101
102
103
|
namespace LivingVillage.Desktop
/// P47 漂浮小元素(鸭子浮标 / 漂浮落叶)原创点阵图集生成器。
/// 复用 P45 `CharacterArt` 的点阵像素代码管线:把 12x8 的字符画按 2x 放大成 24x16 的
/// 单元,4 格一横排(鸭 A/B、叶 A/B)。全部为原创像素画,不采样任何外部素材,
/// 也不使用程序几何矩形冒充成品。
module FloaterArt =
let sourceWidth = 12
let sourceHeight = 8
let scale = 2
let cellWidth = sourceWidth * scale // 24
let cellHeight = sourceHeight * scale // 16
let frameCount = 2
let kindCount = 2
let atlasWidth = cellWidth * frameCount * kindCount // 96
let atlasHeight = cellHeight // 16
let duckIndex = 0
let leafIndex = 1
let private duckFrameA =
[ "............"
"....2222...."
"....2422...."
"...32222...."
"..1111111..."
".111111111.."
".111111111.."
"..5555555..." ]
let private duckFrameB =
[ "............"
".....2222..."
".....2422..."
"....32222..."
"..1111111..."
".111111111.."
".111111111.."
"..5555555..." ]
let private leafFrameA =
[ "............"
".....6......"
"....676....."
"...67776...."
"..6777776..."
"...67776...."
"....676....."
".....6......" ]
let private leafFrameB =
[ "............"
".....6......"
"....676....."
"...67776...."
"..6776776..."
"...67776...."
"....676....."
".....6......" ]
let private colorOf (ch: char) : (int * int * int) option =
match ch with
| '1' -> Some(236, 228, 206) // 鸭身奶白
| '2' -> Some(248, 242, 228) // 鸭头高光
| '3' -> Some(232, 150, 60) // 鸭喙橙
| '4' -> Some(40, 42, 54) // 鸭眼深色
| '5' -> Some(70, 100, 120) // 水面暗线
| '6' -> Some(96, 120, 64) // 叶缘深绿
| '7' -> Some(150, 172, 96) // 叶身浅绿
| _ -> None
/// 单元索引:kind 0=鸭 1=叶,frame 0/1。
let cellIndex (kind: int) (frame: int) : int =
(kind % kindCount) * frameCount + (frame % frameCount)
let sourceRectangle (kind: int) (frame: int) : Microsoft.Xna.Framework.Rectangle =
Microsoft.Xna.Framework.Rectangle(cellIndex kind frame * cellWidth, 0, cellWidth, cellHeight)
let buildAtlas (device: Microsoft.Xna.Framework.Graphics.GraphicsDevice) : Microsoft.Xna.Framework.Graphics.Texture2D =
let data = Array.zeroCreate<Microsoft.Xna.Framework.Color> (atlasWidth * atlasHeight)
let put (index: int) (rows: string list) =
rows
|> List.iteri (fun rowIndex row ->
row
|> Seq.iteri (fun columnIndex ch ->
match colorOf ch with
| None -> ()
| Some(r, g, b) ->
let px = index * cellWidth + columnIndex * scale
for dy in 0 .. scale - 1 do
for dx in 0 .. scale - 1 do
let tx = px + dx
let ty = rowIndex * scale + dy
if tx >= 0 && tx < atlasWidth && ty >= 0 && ty < atlasHeight then
data.[ty * atlasWidth + tx] <- Microsoft.Xna.Framework.Color(r, g, b)))
put (cellIndex duckIndex 0) duckFrameA
put (cellIndex duckIndex 1) duckFrameB
put (cellIndex leafIndex 0) leafFrameA
put (cellIndex leafIndex 1) leafFrameB
let texture = new Microsoft.Xna.Framework.Graphics.Texture2D(device, atlasWidth, atlasHeight)
texture.SetData data
texture
|