"""The smooth look: the WebGL pass compiles, draws, falls back cleanly, and the thermal lens still works.""" import sys, pathlib sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / 'tools')) from use_venv import ensure_playwright; ensure_playwright() from playwright.sync_api import sync_playwright root = pathlib.Path(__file__).resolve().parent.parent out = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else root / 'shots' / 'smooth'); out.mkdir(parents=True, exist_ok=True) fails = [] def check(name, cond, extra=''): print(('PASS ' if cond else 'FAIL ') + name + (f' [{extra}]' if extra != '' else '')) if not cond: fails.append(name) with sync_playwright() as p: b = p.chromium.launch(args=['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader']) pg = b.new_page(viewport={'width': 1024, 'height': 640}) logs = [] pg.on('pageerror', lambda e: logs.append(f'PAGEERROR: {e}')) pg.on('console', lambda m: logs.append(f'{m.type}: {m.text}') if m.type in ('error', 'warning') else None) pg.add_init_script('window.__allowSoftwareGL = true; localStorage.clear();') pg.goto((root / 'dist' / 'index.html').as_uri()); pg.wait_for_timeout(300) pg.click('#btn-new'); pg.fill('#nw-seed', '777'); pg.click('#btn-generate') pg.wait_for_function('GAME.running === true', timeout=20000); pg.wait_for_timeout(1500) ev = pg.evaluate check('the smooth look is the default and is drawing', ev("SET.look === 'smooth' && SM.ok && R.smoothOn"), ev('[SET.look, SM.ok, SM.why, R.smoothOn]')) # the canvas shows the GPU image: sample a sky pixel and a ground pixel, they must differ and not be black px = ev("""(() => { const c = R.ctx.getImageData(R.canvas.width >> 1, 4, 1, 1).data, g = worldToScreenPx(bot.x + 2, surfY[Math.floor(bot.x)] + 6), d = R.ctx.getImageData(Math.round(g.x), Math.round(g.y), 1, 1).data; return [Array.from(c), Array.from(d)]; })()""") check('it draws sky and ground', sum(px[0][:3]) > 200 and px[0][:3] != px[1][:3], px) pg.screenshot(path=str(out / 'smooth.png')) ev("player.lens = true"); pg.keyboard.press('h'); pg.wait_for_timeout(1500) check('the thermal lens draws in pixels', ev('R.lens && !R.smoothOn')) pg.keyboard.press('h'); pg.wait_for_timeout(1500) check('and the smooth look comes back after it', ev('!R.lens && R.smoothOn'), ev('[R.lens, R.smoothOn, SET.look, SM.ok, SM.why, SM.ms, SM.scale]')) ev("SET.look = 'pixel'"); pg.wait_for_timeout(1500) check('the pixel look can be chosen', ev('!R.smoothOn')) pg.screenshot(path=str(out / 'pixel.png')) ev("SET.look = 'smooth'"); pg.wait_for_timeout(1500) ev("SM.scale = 0.5"); pg.wait_for_timeout(1500) st = ev('[R.smoothOn, SM.scale, SM.canvas.width, R.canvas.width, SET.look, SM.ok, SM.why]'); check('half-resolution smooth still draws', (st[0] and st[2] == round(st[3] * st[1])) or st[1] > 0.5, st) # a browser without hardware drawing gets the pixel look and a note pg2 = b.new_page(viewport={'width': 800, 'height': 500}) pg2.add_init_script('localStorage.clear();') pg2.goto((root / 'dist' / 'index.html').as_uri()); pg2.wait_for_timeout(300) pg2.click('#btn-new'); pg2.fill('#nw-seed', '5'); pg2.click('#btn-generate') pg2.wait_for_function('GAME.running === true', timeout=20000); pg2.wait_for_timeout(1200) check('software rendering falls back to pixels with a note', pg2.evaluate("SET.look === 'pixel' && !R.smoothOn && SM.why === 'software'") and pg2.locator('.toast', has_text='graphics card').count() >= 1, pg2.evaluate('[SET.look, SM.why]')) errs = [l for l in logs if 'PAGEERROR' in l or l.startswith('error')] check('no errors', not errs, errs[:3]) b.close() print('FAILS:', fails) sys.exit(1 if fails else 0)