#!/usr/bin/env python3 """Render matched L19 review captures from the L18 and L19 scene exports.""" import os import subprocess from pathlib import Path ROOT = Path(__file__).resolve().parents[4] CAPTURE = ROOT / "Standalone/bin/linux/VoxelForgeOffscreenCapture-linux19-clang" BEFORE = ROOT / "Standalone/Research/WorldAssemblerM3/Linux18/exports" AFTER = ROOT / "Saved/Linux/l19-diagnostics" OUT = ROOT / "Standalone/Research/WorldAssemblerM3/Linux19/captures" PNG_OUT = ROOT / "Saved/Linux/l19-captures-temp" LOGS = ROOT / "Saved/Linux/l19-diagnostics" OUT.mkdir(parents=True, exist_ok=True) PNG_OUT.mkdir(parents=True, exist_ok=True) env = os.environ.copy() env["LP_NUM_THREADS"] = "12" env["XDG_CACHE_HOME"] = str(ROOT / "Saved/Linux/mesa-cache") views = [ ("floating-islands-flat-square-before", BEFORE / "floating-islands-flat-square.vfmesh", (-11.612444, -118.221237, -19.8452), 0, 0, True), ("floating-islands-flat-square-after", AFTER / "floating-islands-flat-square-after.vfmesh", (-11.612444, -118.221237, -19.8452), 0, 0, True), ("floating-islands-owner-angle-before", BEFORE / "floating-islands-island-view.vfmesh", (-22, -19, -22.8), 0, -4, True), ("floating-islands-owner-angle-after", AFTER / "floating-islands-island-view-after.vfmesh", (-22, -19, -22.8), 0, -4, True), ("floating-islands-owner-ground-before", AFTER / "floating-islands-owner-ground-before.vfmesh", (-6.3, -19.06, -21.0), 0, -4, True), ("floating-islands-owner-ground-after", AFTER / "floating-islands-owner-ground-after.vfmesh", (-6.3, -19.06, -21.0), 0, -4, True), ("floating-islands-ceiling-up-after", AFTER / "floating-islands-island-view-after.vfmesh", (-22, -19, -22.8), 0, 80, True), ("surface-world-l1-spawn-before", BEFORE / "surface-world-l1-spawn.vfmesh", (0, -35, -487.94), 0, -22, False), ("surface-world-l1-spawn-after", AFTER / "surface-world-l1-spawn-after.vfmesh", (0, -35, -487.94), 0, -22, False), ("surface-world-horizon-before", BEFORE / "surface-world-l1-spawn.vfmesh", (0, -35, -487.94), 0, 0, False), ("surface-world-horizon-after", AFTER / "surface-world-l1-spawn-after.vfmesh", (0, -35, -487.94), 0, 0, False), ("surface-world-rings-above-before", BEFORE / "surface-world-l1-spawn.vfmesh", (0, -35, -280), 0, -90, True), ("surface-world-rings-above-after", AFTER / "surface-world-l1-spawn-after.vfmesh", (0, -35, -280), 0, -90, True), ] for name, scene, camera, yaw, pitch, tile_edges in views: if not scene.exists(): raise SystemExit(f"missing scene: {scene}") png = PNG_OUT / f"{name}.png" jpg = OUT / f"{name}.jpg" render_log = LOGS / f"{name}-render.log" convert_log = LOGS / f"{name}-jpeg.log" command = [str(CAPTURE), str(scene), str(png), "--size=1600x900", "--shade=readable", f"--tile-edges={'on' if tile_edges else 'off'}", "--tile-edge-width-m=0.15", "--camera-m="+",".join(map(str, camera)), f"--yaw-deg={yaw}", f"--pitch-deg={pitch}"] with render_log.open("w", encoding="utf-8") as stream: subprocess.run(command, cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT, check=True) ffmpeg = ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error", "-y", "-i", str(png), "-frames:v", "1", "-q:v", "4", str(jpg)] with convert_log.open("w", encoding="utf-8") as stream: subprocess.run(ffmpeg, cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT, check=True) if jpg.stat().st_size > 300_000: raise SystemExit(f"{jpg.name} exceeds the 300 KB review limit") print(f"[Capture] {jpg.relative_to(ROOT)} bytes={jpg.stat().st_size} status=PASS", flush=True)