• src/doors/syncretro/syncr

    From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Tue Jul 21 01:41:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/990418baddfa1cbfa276ed88
    Modified Files:
    src/doors/syncretro/syncretro.h syncretro_input.c syncretro_io.c
    Log Message:
    syncretro: hide the client's status line to reclaim its row

    A terminal that shows a status line reserves its bottom text row for it -- SyncTERM's default turns an 80x25 / 640x400 client into an 80x24 / 640x384 canvas -- so the door fractionally downscales every frame and loses single-pixel detail for nothing. That row matters more here than for a landscape console: an upright arcade game is height-bound.

    termgfx has had the DECSSDT seam for this all along, and syncduke, syncdoom, syncconquer and syncscumm all use it; SyncRetro was the one door that never adopted it. Emit termgfx_term_status_off BEFORE the canvas probe so the
    probe reports the reclaimed size -- after it, the door would scale to the
    old canvas and the row would go to waste.

    The sequence is prefixed with a DECRQSS query of the current setting; syncretro_input.c captures the reply (rolling window, since a 10-byte DCS
    can arrive split over a BBS link) so sr_io_leave() restores the player's
    status line to what it WAS rather than guessing. The BBS lent us the
    terminal; a door that hides the sysop's status line and never puts it back
    has broken his client. Falls back to 1 (indicator, SyncTERM's own default)
    if the terminal never answers. Terminals with no status line, or no
    DECSSDT, ignore the whole thing.
    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Tue Jul 21 01:41:00 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/39b1af971b321423aeebf3c2
    Added Files:
    src/doors/syncretro/syncretro_dirty.c syncretro_dirty.h test_dirty.c Modified Files:
    src/doors/syncretro/CMakeLists.txt syncretro.h syncretro_config.c syncretro_io.c xtrn/syncarcade/syncretro.example.ini
    Log Message:
    syncretro: patch the changed cells instead of repainting the frame

    A console redraws its whole framebuffer every frame, but very little of it MOVES: Pac-Man's maze is static while five sprites and a scatter of dots are not. The terminal is already holding the last frame and a sixel image can be drawn at any character cell, so the cells that changed can be painted over it and the rest left alone -- sending the movement rather than the picture.

    New syncretro_dirty.c is the geometry half and nothing else: no encoding, no terminal, no I/O. It diffs two scaled index buffers, labels 4-connected components of changed cells, merges boxes within a cell of each other, and returns up to 12 rectangles. Diffing the SCALED frame on the TERMINAL'S CELL GRID is what keeps it simple -- a sixel can only be placed at a cell corner, so finding rectangles on cell boundaries means every one comes out directly placeable and the caller never snaps or adjusts one. (../syncconquer does the same job against its native framebuffer on a fixed 16px grid and maps the result through its scaler; worth folding into termgfx if a third door wants it.)

    Every precondition in syncretro_io.c is a correctness one, and a failed one falls through to the whole-frame path, which is always right: a forced repaint (a door screen painted over the game), a changed palette (the pixels the client holds no longer mean what they did), moved or resized geometry, no previous scaled frame, or a terminal that does not persist sixel colour registers -- where a palette per rectangle would cost far more than one frame, so only SyncTERM takes this path. It also gives up when nothing changed, when >= 40% of cells did, or when the change is too fragmented to describe cheaply.

    test_dirty.c pins the two properties a coalescing bug breaks: the rectangles COVER every differing pixel -- checked exhaustively, because a miss leaves stale pixels on the player's screen until the next full frame -- and they stay cell-aligned and inside the frame. Cases are the real ones: a sprite that moves, one straddling a cell boundary, four in the corners (which must NOT become one bounding box), a full-screen flash, scattered noise, a partial edge cell under metrics that divide neither axis.

    Ctrl-S gains a "dr N%" field (the share of frames patched rather than repainted, or "dr off"), and the door logs a one-line video summary on exit. [video] dirty_rect = false disables it.

    Verified live against MAME 2003-Plus over SyncTERM: a large reduction in bytes per frame, and the forced-repaint path confirmed -- returning from the pause and help screens repaints in full, so nothing stale can survive a door screen. ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net