• src/doors/syncretro/syncretro_quant.c syncretro_quant.hsrc/doors/syncr

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Thu Jul 9 01:55:11 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/faa2969bcda1e1c9736e7246
    Added Files:
    src/doors/syncretro/syncretro_quant.c syncretro_quant.h
    Modified Files:
    src/doors/syncretro/CMakeLists.txt DESIGN.md README.md main.c retro_bridge.c retro_core.c retro_core.h syncretro.h syncretro_config.c syncretro_door.c syncretro_input.c syncretro_io.c
    Log Message:
    syncretro: fill in M1, the video-only vertical slice

    The frontend now loads a core, loads a ROM, renders frames as sixel, maps terminal keys onto a RetroPad, paces on DSR-ACK, and restores the BBS
    terminal on every exit path. Audio is accepted and discarded (DESIGN.md
    sec 8 defers streaming console PCM to M4; it was never a launch blocker).

    Two pieces have no counterpart in the sibling doors, because a libretro
    core is not a fixed-format engine:

    * syncretro_quant.c -- the frame is truecolor, where DOOM/Duke/1oom all
    render into an 8-bit palette, and sixel is a 256-color format. With
    256 or fewer distinct colors -- every legacy console -- the palette IS
    the frame's colors and the reduction is exact. The palette is built
    sorted, so it depends only on the color SET: a frame redrawn from the
    same colors yields a byte-identical palette and the sixel color
    registers are sent once. Busier frames fall back to a fixed 6x6x6 cube
    plus a 40-step gray ramp.

    * The frame SIZE is not a compile-time constant and a core may change it
    mid-session, so every buffer grows on demand and the image rect is
    recomputed on a source-size change, not only on a probe reply.

    Input is the interesting part. A RetroPad is a held-state device -- the
    core asks "is UP down right now?" every frame -- but a terminal sends
    bytes on press and nothing on release. Three paths, negotiated at connect, climbing the same ladder syncduke does for Build's scancode queue: evdev physical key reports on SyncTERM (CTDA cap 8; layout-independent, so WASD
    works on AZERTY), the kitty keyboard protocol elsewhere, and an
    auto-release timer where neither exists. Whichever mode is negotiated is
    undone on exit, as in the sibling doors.

    Resolve the core and ROM paths against the launch directory before sr_config_apply() chdir's into the per-user sandbox, and search a roms/ subdirectory for cartridges. Without the absolutize, a relative ROM path
    was looked up inside the sandbox and never found; cores also keep the
    directory pointers they are handed for the whole session.

    Verified end to end against FreeIntv: with no BIOS the core still loads
    the cartridge, halts, and draws its own "PUT GROM/EXEC IN SYSTEM
    DIRECTORY" screen, which decodes cleanly out of a SYNCRETRO_SIXELOUT
    capture -- so the BIOS gates playing a game, not exercising the frontend. Pacing, backpressure, the carrier drop and all three key paths are
    covered by a synthetic core and a fake terminal on a socketpair (~/tmp/syncretro_probes). Builds warning-free under gcc and clang.

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net