#!/usr/bin/env python3 """ regress.py -- cross-scene regression: replay every scene capture through the board + renderer, save a PNG each, report errors/timing. Also self-tests sect_vector picking against the SHARKS scene. python regress.py """ import os, sys, struct, time, traceback sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) os.environ.setdefault('SDL_VIDEODRIVER', 'dummy') import numpy as np from vrboard import VirtualBoard, Assembler, A, pack_vr from decode_anim import find_framed_start SCENES = [ ('SHARKS', 'cap8.raw.bin', 2000), ('SDEMO', 'sdemo2.raw.bin', 800), ('KLNGVID', 'klng.raw.bin', 900), ('BLADE', 'blade2.raw.bin', 300), ('FXTEST', 'fxtest.raw.bin', 400), ] def replay(path, upto): data = open(path, 'rb').read() board = VirtualBoard() asm = Assembler(); asm.feed(data[find_framed_start(data):]) errs = 0 for m in asm: try: board.handle(m) except Exception: errs += 1 if board.frames >= upto: break return board, errs def main(): from vrview import Renderer r = Renderer() ok = True soft_frames = {} for name, path, upto in SCENES: if not os.path.exists(path): print(f'{name:8} SKIP (no capture {path})') continue try: board, herrs = replay(path, upto) board._view = r r.cache = type(r.cache)() # fresh SceneCache per scene t0 = time.perf_counter() r.frame = 0; r.skip = 1 r.draw(board) ms = (time.perf_counter() - t0) * 1000 r.pygame.image.save(r.screen, f'regress_{name.lower()}.png') soft_frames[name] = r.last_frame.copy() print(f'{name:8} OK frame={ms:6.0f}ms instances={len(r.cache.instances):4} ' f'lights={len(r.cache.dirlights)}+amb handler-errors={herrs}') except Exception: ok = False print(f'{name:8} FAIL') traceback.print_exc() # ---- GPU backend pass (moderngl, headless standalone context) ---------- # Same scenes through vrview_gl.GLRenderer: PNG each, sustained-frame # timing (VBOs cached after frame 1), and a mean-abs-diff sanity check # against the software reference at the same resolution. try: from vrview_gl import GLRenderer g = GLRenderer() # native 832x512 target res print(f'-- GL backend: {g.ctx.info["GL_RENDERER"]} {g.w}x{g.h} --') for name, path, upto in SCENES: if not os.path.exists(path): continue try: board, _ = replay(path, upto) board._view = g g.cache = type(g.cache)() g.frame = 0; g.skip = 1 g.draw(board) # frame 1: VBO/texture upload t0 = time.perf_counter(); N = 20 for _i in range(N): # sustained: uniforms only g.skip = 1 g.draw(board) ms = (time.perf_counter() - t0) * 1000 / N arr = g.last_frame pgs = g.pygame.image.frombuffer(arr.tobytes(), (g.w, g.h), 'RGB') g.pygame.image.save(pgs, f'regress_gl_{name.lower()}.png') diff = '' sf = soft_frames.get(name) if sf is not None: import pygame as _pg small = _pg.transform.smoothscale(pgs, (sf.shape[1], sf.shape[0])) sa = np.transpose(_pg.surfarray.array3d(small), (1, 0, 2)) diff = (f' diff-vs-soft=' f'{np.abs(sf.astype(int) - sa.astype(int)).mean():.1f}/255') print(f'{name:8} GL frame={ms:6.1f}ms ({1000/max(ms,1e-3):5.0f}fps)' f'{diff}') except Exception: ok = False print(f'{name:8} GL FAIL') traceback.print_exc() except Exception as e: print(f'-- GL backend unavailable ({e}) -- skipped --') # sect_vector self-test on SHARKS: ray from the camera into the fish cluster board, _ = replay('cap8.raw.bin', 2000) board._view = r r.cache = type(r.cache)() reply = board.handle_sect_test = None p = struct.pack('<4f6f', 0, 0, 0, 0, 0, 5, 5, -460, 380, -430) rep = board.do_sect_vector(p) act, = struct.unpack_from(' fish cluster): instance handle {h:#x} ' f'({"HIT" if h else "miss"})') p2 = struct.pack('<4f6f', 0, 0, 0, 0, 0, 5, 5, 0, 5000, 5) h2 = struct.unpack_from('