summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop/FloaterArt.fs
diff options
context:
space:
mode:
Diffstat (limited to 'src/LivingVillage.Desktop/FloaterArt.fs')
-rw-r--r--src/LivingVillage.Desktop/FloaterArt.fs103
1 files changed, 103 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop/FloaterArt.fs b/src/LivingVillage.Desktop/FloaterArt.fs
new file mode 100644
index 0000000..53a0793
--- /dev/null
+++ b/src/LivingVillage.Desktop/FloaterArt.fs
@@ -0,0 +1,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