#!/usr/bin/env python3 """Capture one arrival-mouth eye view per Core.Liminal.Field v2 variant.""" from __future__ import annotations import hashlib import json import math import os from pathlib import Path import subprocess import sys import time ROOT = Path(__file__).resolve().parents[4] HERE = Path(__file__).resolve().parent OUT = ROOT / "Saved/Linux/l145" CAPTURES = HERE / "captures" LIMIT = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--"] Q_PER_METRE = 1024.0 sys.path.insert(0, str(ROOT / "Standalone/Tools/verify")) from runner import bounded_run, current_stamp, first_stamp def fmt(values) -> str: return ",".join(f"{value:.6f}" for value in values) def sha256(path: Path) -> str: digest = hashlib.sha256() with path.open("rb") as stream: for block in iter(lambda: stream.read(1024 * 1024), b""): digest.update(block) return digest.hexdigest() def run_step(name: str, command: list[object], log: Path, env: dict[str, str], stamped: bool = False) -> str: expected_stamp = current_stamp() if stamped else None if stamped: binary = Path(str(command[0])) probe = bounded_run([str(binary), "--print-source-stamp"], timeout=15) if probe is None or probe.returncode != 0 \ or first_stamp(probe.stdout or "") != expected_stamp: raise RuntimeError(f"{name} refused a stale executable: {binary}") started = time.monotonic() log.parent.mkdir(parents=True, exist_ok=True) with log.open("w", encoding="utf-8") as stream: result = subprocess.run([*LIMIT, "timeout", "1740s", *map(str, command)], cwd=ROOT, env=env, stdout=stream, stderr=subprocess.STDOUT, timeout=1745, check=False) output = log.read_text(encoding="utf-8", errors="replace") elapsed = time.monotonic() - started print(f"[L145Run] step={name} elapsed_s={elapsed:.3f} exit={result.returncode} log={log}", flush=True) if stamped and (first_stamp(output) != expected_stamp or current_stamp() != expected_stamp): raise RuntimeError(f"{name} source stamp mismatch; see {log}") if result.returncode != 0: raise RuntimeError(f"{name} exit={result.returncode}; see {log}") return output def camera_angles(camera, target): dx, dy, dz = (target[i] - camera[i] for i in range(3)) return math.degrees(math.atan2(dx, dy)), math.degrees( math.atan2(dz, math.hypot(dx, dy))) def route_views(manifest_path: Path, layout_path: Path, name: str): manifest = json.loads(manifest_path.read_text(encoding="utf-8")) layout = json.loads(layout_path.read_text(encoding="utf-8")) plan = next(row for row in manifest["plan"]["strates"] if row["strate_index"] == 1 and row.get("liminal_field", {}).get("version") == 2) points = [tuple(value / Q_PER_METRE for value in row["position_q"]) for row in plan["route"]] first, second = points[0], points[1] dx, dy = second[0] - first[0], second[1] - first[1] length = math.hypot(dx, dy) if length <= 1.0e-6: raise RuntimeError("Core.Liminal.Field arrival tangent is degenerate") tx, ty = dx / length, dy / length eye_camera = (first[0] - tx * 1.5, first[1] - ty * 1.5, first[2] + 1.6) third = points[min(2, len(points) - 1)] dx, dy = third[0] - first[0], third[1] - first[1] tangent_length = math.hypot(dx, dy) tx, ty = dx / tangent_length, dy / tangent_length dz_per_metre = (third[2] - first[2]) / tangent_length eye_target = (first[0] + tx * 40.0, first[1] + ty * 40.0, first[2] + dz_per_metre * 40.0 + 1.6) middle = len(points) // 2 before, center, after = points[middle - 1], points[middle], points[middle + 1] dx, dy = after[0] - before[0], after[1] - before[1] length = math.hypot(dx, dy) if length <= 1.0e-6: raise RuntimeError("Core.Liminal.Field wide-view tangent is degenerate") tx, ty = dx / length, dy / length nx, ny = -ty, tx floor = plan["liminal_field"]["floor_height_q"] / Q_PER_METRE if name == "flatField-monolith": monolith = next(row for row in layout.get("stamps", []) if row.get("stable_id") == "core/liminal-field/monolith/000") monolith_center = tuple(value / 1.0e6 for value in monolith["position_um"]) floor = monolith_center[2] - monolith["half_extents_um"][2] / 1.0e6 wide_camera = (monolith_center[0] - tx * 30.0 + nx * 18.0, monolith_center[1] - ty * 30.0 + ny * 18.0, floor + 25.0) wide_target = monolith_center elif name == "periodicHills": wide_camera = (center[0] - 20.0, center[1] - 25.0, floor + 10.0) wide_target = (center[0] + 10.0, center[1] + 8.0, floor + 1.0) elif name == "pillar-grid": pillars = [row for row in layout.get("stamps", []) if row.get("stable_id", "").startswith("core/liminal-field/pillars/")] if not pillars: raise RuntimeError("pillar-grid layout has no resolved grid stamps") pairs = [] for i, first_pillar in enumerate(pillars): for second_pillar in pillars[i + 1:]: a = first_pillar["position_um"] b = second_pillar["position_um"] dx, dy = (b[0] - a[0]) / 1.0e6, (b[1] - a[1]) / 1.0e6 separation = math.hypot(dx, dy) if 60.0 <= separation <= 90.0: mx = (a[0] + b[0]) / 2.0e6 my = (a[1] + b[1]) / 2.0e6 pairs.append((math.hypot(mx - center[0], my - center[1]), mx, my, dx / separation, dy / separation, (a[2] + b[2]) / 2.0e6, first_pillar["half_extents_um"][2] / 1.0e6)) if not pairs: raise RuntimeError("pillar-grid has no neighboring resolved columns") _, mx, my, tx, ty, pillar_z, half_height = min(pairs) floor = pillar_z - half_height nx, ny = -ty, tx wide_camera = (center[0] - tx * 20.0 + nx * 25.0, center[1] - ty * 20.0 + ny * 25.0, center[2] + 8.0) wide_target = (center[0], center[1], floor + 2.0) else: wide_camera = (center[0] - tx * 20.0 + nx * 25.0, center[1] - ty * 20.0 + ny * 25.0, center[2] + 8.0) wide_target = (center[0], center[1], floor + 2.0) return {"eye": (eye_camera, eye_target), "wide": (wide_camera, wide_target)} def capture_variant(seed: int, name: str, *, headless: Path, renderer: Path, fixture: Path, env: dict[str, str]): stem = f"core-liminal-{name}-seed{seed:02d}" plan_dir = OUT / "capture-plans" / stem plan_dir.mkdir(parents=True, exist_ok=True) manifest = plan_dir / "manifest.json" layout = plan_dir / "layout.json" command = [headless, fixture, "--workers=1", f"--seed={seed}", "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", "--force-generate", "--clip-radius=1", "--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0", "--camera=0,0,-540,0,0", f"--world-assembler-manifest-output={manifest}", f"--resolved-layout-output={layout}"] output = run_step(f"plan-{stem}", command, OUT / "logs" / f"capture-{stem}-plan.log", env, stamped=True) if "[CoreLiminalFieldDraw]" not in output: raise RuntimeError(f"{stem} plan omitted its Core liminal deck") views = route_views(manifest, layout, name) for view, (eye, target) in {"eye": views["eye"]}.items(): work = OUT / "captures" / f"{stem}-{view}" work.mkdir(parents=True, exist_ok=True) view_manifest = work / "manifest.json" view_layout = work / "layout.json" mesh = work / "world.vfmesh" yaw, pitch = camera_angles(eye, target) camera = (*eye, yaw, pitch) view_clip_radius = (5 if view == "wide" and name in { "flatField-monolith", "periodicHills"} else 3) command = [headless, fixture, "--workers=12", f"--seed={seed}", "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", "--force-generate", f"--clip-radius={view_clip_radius}", "--max-clip-level=0", "--max-level=0", "--render-distance-chunks=0", "--capture-skip-walkability", f"--camera={fmt(camera)}", f"--mesh-export={mesh}", f"--world-assembler-manifest-output={view_manifest}", f"--resolved-layout-output={view_layout}"] output = run_step(f"export-{stem}-{view}", command, OUT / "logs" / f"capture-{stem}-{view}-export.log", env, stamped=True) if "[CoreLiminalFieldDraw]" not in output or not mesh.is_file() \ or mesh.stat().st_size == 0: raise RuntimeError(f"{stem}-{view} export omitted its Core liminal deck or mesh") png = work / f"{view}.png" image = CAPTURES / f"{stem}-{view}.jpg" fog = { "flatField-monolith": (30, 180, "0.66,0.73,0.77", -708.0, 46.0), "periodicHills": (140, 850, "0.78,0.84,0.88", -720.0, 14.0), "road-over-cloud-floor": (24, 420, "0.88,0.93,0.95", -720.0, 65.0), "pillar-grid": (180, 1200, "0.82,0.88,0.91", -720.0, 80.0), }[name] fog_start, fog_end, fog_color, height_center, height_range = fog render = [renderer, mesh, png, "--size=1600x900", "--fov-deg=72", f"--camera-m={fmt(eye)}", f"--yaw-deg={yaw:.6f}", f"--pitch-deg={pitch:.6f}", "--tile-skirts=on", "--shade=readable", "--headlamp=off", "--height-tint=on", f"--height-center-m={height_center:.6f}", f"--height-range-m={height_range:.6f}", "--light-direction=-0.42,-0.58,0.70", "--fog=on", f"--fog-start-m={fog_start}", f"--fog-end-m={fog_end}", f"--fog-color={fog_color}"] run_step(f"render-{stem}-{view}", render, OUT / "logs" / f"capture-{stem}-{view}-render.log", env, stamped=True) run_step(f"jpeg-{stem}-{view}", ["ffmpeg", "-nostdin", "-hide_banner", "-loglevel", "error", "-y", "-i", png, "-frames:v", "1", "-q:v", "4", image], OUT / "logs" / f"capture-{stem}-{view}-jpeg.log", env) run_step(f"quality-{stem}-{view}", [sys.executable, ROOT / "Standalone/Tools/verify/capture_quality.py", image], OUT / "logs" / f"capture-{stem}-{view}-quality.log", env) print(f"[L145Capture] variant={name} seed={seed} view={view} " f"eye_height={'1.600m' if view == 'eye' else 'wide'} bytes={image.stat().st_size} " f"sha256={sha256(image)} status=PASS", flush=True) def main() -> int: headless = ROOT / "Standalone/bin/linux/VoxelForgeCoreHeadless-l145-clang" renderer = ROOT / "Standalone/bin/linux/VoxelForgeOffscreenCapture-l145-clang" fixture = OUT / "fixtures/core-liminal-field-3-strata.json" env = os.environ.copy() env["VOXELFORGE_VERIFY_OUT"] = str(OUT) env["VOXELFORGE_OWNER_DATA"] = str(ROOT / "Standalone/data/owner_world.json") env["LP_NUM_THREADS"] = "12" env["XDG_CACHE_HOME"] = str(OUT / "xdg-cache") CAPTURES.mkdir(parents=True, exist_ok=True) variants = ("flatField-monolith", "periodicHills", "road-over-cloud-floor", "pillar-grid") selected = set(os.environ.get("L145_CAPTURE_VARIANTS", "").split(",")) for seed, name in enumerate(variants): if selected and name not in selected: continue capture_variant(seed, name, headless=headless, renderer=renderer, fixture=fixture, env=env) return 0 if __name__ == "__main__": try: raise SystemExit(main()) except Exception as error: print(f"[L145Capture] status=FAIL error={error}", file=sys.stderr, flush=True) raise SystemExit(1)