• src/doors/syncretro/syncretro_io.c test_dirty.c

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Fri Aug 7 01:29:30 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/e2a4cacb378a4313c37f70d6
    Modified Files:
    src/doors/syncretro/syncretro_io.c test_dirty.c
    Log Message:
    syncretro: size every patch in whole sixel bands, not just whole cells

    A dirty-rect patch was sized in whole text cells, which is what the cursor address in front of it needs. It is not what the decoder behind it needs.
    A sixel is read six pixel rows at a time, and SyncTERM's 8x16 cell makes patches 16, 32 and 80 rows tall -- none of them a whole number of bands,
    so every patch ended in a partial one.

    cterm did not clear its band mask between bands until d65cb83886
    (2026-06-28). Below that, any column of a partial final band not covered
    by the band's first colour keeps the PREVIOUS band's pixels, and the band
    is blitted full height regardless. Each patch therefore left a stale
    sliver at its foot, which a sprite moving across the screen smears into a dotted trail behind it. SourceForge #258; reported against SyncArcade as
    GitLab #1214 once b3caee6dd4 (2026-08-04) made patches land where they
    were addressed and the trail became visible.

    Only SyncTERM was exposed. Every other terminal already took the
    band_align path, which snaps a rect to LCM(cell, 6) and so has always
    emitted whole bands; SyncTERM was passed band_align=0 on the reasoning
    that a cell-anchored patch is enough. Cell alignment is not band
    alignment, and 16 is not a multiple of 6.

    So band_align now applies to every sixel client. The height rounding in
    the geometry routine moves with it: it kept the image an exact multiple of
    the cell height precisely so band_align's hcell clamp could never strand a sub-cell remainder, and it was gated on the same condition. Splitting the
    two would trade a stale sliver under each patch for a stale strip along
    the bottom of the frame.

    Measured over a 14-second capture against a 1.327 peer: 51 of 53 sixels
    had a partial final band before, none after; patch heights go 16/32/80 -> 48/96, and the wire grows 26559 -> 27267 bytes, 2.7%. The added rows are unchanged background and cost almost nothing once run-length encoded.

    test_dirty pins the property the terminals actually depend on -- a rect
    height divisible by six -- across cell heights 16, 8, 13, 7, 6 and 5,
    rather than the LCM of one particular cell.

    Reported by Keyop.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

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