diff options
Diffstat (limited to 'src/LivingVillage.Desktop/Game.fs')
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 125 |
1 files changed, 110 insertions, 15 deletions
diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index e48888e..64dc3e2 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -188,11 +188,42 @@ type LivingVillageGame() as this = [ (1, 1); (255, 191); (509, 381); (256, 60); (256, 300); (80, 200); (430, 300) ] let mutable tourIndex = 0 let mutable tourFrame = 0 + // P20 证据钩子:LV_MAPGEN_SHOT=1 时用参数化生成器出整图 + 视口裁剪帧,拍完即退出。 + let mapGenShotMode = Environment.GetEnvironmentVariable("LV_MAPGEN_SHOT") = "1" + let mapGenWidth = + match Environment.GetEnvironmentVariable("LV_MAPGEN_WIDTH") with + | null | "" -> 256 + | v -> match Int32.TryParse v with (true, value) when value > 0 -> value | _ -> 256 + let mapGenHeight = + match Environment.GetEnvironmentVariable("LV_MAPGEN_HEIGHT") with + | null | "" -> 192 + | v -> match Int32.TryParse v with (true, value) when value > 0 -> value | _ -> 192 + let mapGenSeed = + match Environment.GetEnvironmentVariable("LV_MAPGEN_SEED") with + | null | "" -> 4242UL + | v -> match UInt64.TryParse v with (true, value) -> value | _ -> 4242UL + let mutable mapGenResult = Unchecked.defaultof<MapGen.Result> + let mutable mapGenGenMs = 0.0 do if scale > 1 then Sim.configureBounds (64 * scale) (48 * scale) ProceduralMap.activate (uint64 4242) + if mapGenShotMode then + let stopwatch = System.Diagnostics.Stopwatch.StartNew() + mapGenResult <- MapGen.generateWithSize mapGenWidth mapGenHeight mapGenSeed + stopwatch.Stop() + mapGenGenMs <- stopwatch.Elapsed.TotalMilliseconds + printfn + "mapgen-gen size=%dx%d seed=%d gen_ms=%.2f tiles=%d reachable_ok=%b reachable_tiles=%d spawns=%d" + mapGenResult.Width + mapGenResult.Height + (int mapGenResult.Seed) + mapGenGenMs + mapGenResult.Tiles.Length + mapGenResult.ReachabilityOk + mapGenResult.ReachableTiles + mapGenResult.Spawns.Length if mapTourMode then tourWaypoints <- [ (1, 1); (Sim.mapWidthTiles / 2, Sim.mapHeightTiles / 2); (Sim.mapWidthTiles - 3, Sim.mapHeightTiles - 3) @@ -659,23 +690,87 @@ type LivingVillageGame() as this = printfn "menu-shot=done frames=%d" menuShotFrame this.Exit() + /// P20 证据:把一次 MapGen 绘制渲染到离屏 target 并落盘,返回绘制瓦片数。 + member private this.RenderMapGen (drawFitted: bool) : int * Texture2D = + let viewport = this.GraphicsDevice.Viewport + use target = new RenderTarget2D(this.GraphicsDevice, viewport.Width, viewport.Height) + this.GraphicsDevice.SetRenderTarget target + this.GraphicsDevice.Clear(Color(18, 26, 20)) + let camX = max 0 ((mapGenResult.Width * Sim.tilePixels - viewport.Width) / 2) + let camY = max 0 ((mapGenResult.Height * Sim.tilePixels - viewport.Height) / 2) + spriteBatch.Begin() + let drawn = + if drawFitted then + VillageArt.drawMapFitted spriteBatch artTextures viewport.Width viewport.Height mapGenResult Color.White + else + VillageArt.drawMapViewport spriteBatch artTextures (Vector2(float32 camX, float32 camY)) viewport.Width viewport.Height mapGenResult 0L Color.White + spriteBatch.End() + this.GraphicsDevice.SetRenderTarget null + let data = Array.zeroCreate<Color> (viewport.Width * viewport.Height) + target.GetData<Color>(data) + let texture = new Texture2D(this.GraphicsDevice, viewport.Width, viewport.Height) + texture.SetData(data) + (drawn, texture) + + /// P20 证据:整图等比渲染 + 1:1 视口裁剪帧各存一张,打印绘制计数后退出。 + member private this.DrawMapGenShot () = + System.IO.Directory.CreateDirectory recordDirectory |> ignore + let viewport = this.GraphicsDevice.Viewport + let fittedDrawn, fittedTexture = this.RenderMapGen true + use _fitted = fittedTexture + use stream = System.IO.File.Create(sprintf "%s/mapgen-%dx%d-seed%d.png" recordDirectory mapGenResult.Width mapGenResult.Height (int mapGenResult.Seed)) + fittedTexture.SaveAsPng(stream, viewport.Width, viewport.Height) + printfn "mapgen-fitted drawn=%d viewport=%dx%d" fittedDrawn viewport.Width viewport.Height + + let camX = max 0 ((mapGenResult.Width * Sim.tilePixels - viewport.Width) / 2) + let camY = max 0 ((mapGenResult.Height * Sim.tilePixels - viewport.Height) / 2) + let culledDrawn, culledTexture = this.RenderMapGen false + use _culled = culledTexture + use culledStream = System.IO.File.Create(sprintf "%s/mapgen-culled-%dx%d-seed%d.png" recordDirectory mapGenResult.Width mapGenResult.Height (int mapGenResult.Seed)) + culledTexture.SaveAsPng(culledStream, viewport.Width, viewport.Height) + let total = mapGenResult.Width * mapGenResult.Height + let visible = MapGen.visibleTileCount mapGenResult.Width mapGenResult.Height camX camY viewport.Width viewport.Height + printfn "mapgen-cull drawn=%d visible=%d total=%d culled=%.1f%%" culledDrawn visible total (100.0 * (1.0 - float culledDrawn / float total)) + + let smallWatch = System.Diagnostics.Stopwatch.StartNew() + let smallMap = MapGen.generateWithSize 64 48 (uint64 4242) + smallWatch.Stop() + printfn "mapgen-gen-legacy size=%dx%d gen_ms=%.2f tiles=%d reachable_ok=%b" smallMap.Width smallMap.Height smallWatch.Elapsed.TotalMilliseconds smallMap.Tiles.Length smallMap.ReachabilityOk + + let frameWatch = System.Diagnostics.Stopwatch.StartNew() + use frameTarget = new RenderTarget2D(this.GraphicsDevice, viewport.Width, viewport.Height) + this.GraphicsDevice.SetRenderTarget frameTarget + for _ in 1 .. 30 do + spriteBatch.Begin() + VillageArt.drawMapViewport spriteBatch artTextures (Vector2(float32 camX, float32 camY)) viewport.Width viewport.Height mapGenResult 0L Color.White |> ignore + spriteBatch.End() + this.GraphicsDevice.SetRenderTarget null + frameWatch.Stop() + let perFrameMs = frameWatch.Elapsed.TotalMilliseconds / 30.0 + printfn "mapgen-frame avg_ms=%.2f implied_fps=%.1f iterations=30" perFrameMs (1000.0 / perFrameMs) + printfn "mapgen-shot=done" + this.Exit() + override this.Draw(gameTime: GameTime) = - if splashActive then - this.DrawSplash() - elif menu.Page <> Playing then - this.DrawMenu() - elif relationView then - this.DrawRelationView() - this.DrawM5Overlay() + if mapGenShotMode then + this.DrawMapGenShot() else - this.DrawWorldView() - if recordMode && sampleMode then - recordIndex <- recordIndex + 1 - if recordIndex % recordEvery = 0 then - System.IO.Directory.CreateDirectory recordDirectory |> ignore - this.SaveBackBuffer(sprintf "%s/rec-frame-%04d.png" recordDirectory recordIndex) - if menuShotMode then - this.CaptureMenuShot() + if splashActive then + this.DrawSplash() + elif menu.Page <> Playing then + this.DrawMenu() + elif relationView then + this.DrawRelationView() + this.DrawM5Overlay() + else + this.DrawWorldView() + if recordMode && sampleMode then + recordIndex <- recordIndex + 1 + if recordIndex % recordEvery = 0 then + System.IO.Directory.CreateDirectory recordDirectory |> ignore + this.SaveBackBuffer(sprintf "%s/rec-frame-%04d.png" recordDirectory recordIndex) + if menuShotMode then + this.CaptureMenuShot() /// 启动画面:分层天色 + 屋脊/水面剪影 + 标题淡入上浮 + 跳过提示,全部为帧计数纯函数。 member private this.DrawSplash() = |
