• src/doors/termgfx/termgfx_termio.c termgfx_termio.h

    From Rob Swindell (on Debian Linux)@VERT to Git commit to main/sbbs/master on Sunday, July 19, 2026 23:59:33
    https://gitlab.synchro.net/main/sbbs/-/commit/4668dc2f1f2cd8a9f0b27a84
    Modified Files:
    src/doors/termgfx/termgfx_termio.c termgfx_termio.h
    Log Message:
    termgfx: add a truecolor (XRGB) present entry point to termgfx_termio

    Add termgfx_termio_present_rgbx(xrgb, w, h), a sibling of the existing
    indexed termgfx_termio_present() that takes a native-resolution 32-bit
    frame (memory byte order R,G,B,X; the 4th byte is ignored padding;
    stride w*4) instead of an 8-bit-indexed frame plus palette. It is the
    entry point the upcoming syncrpg door needs, where the source surface is truecolor with no fixed palette of its own.

    The new path mirrors present()'s tier / geometry / pacing flow but
    produces the encoder input from XRGB:

    - sixel tier: nearest-neighbor scale the XRGB frame to packed RGB888 at
    the fit ew x eh, quantize it with the shared termgfx_quant_rgb(), then
    sixel_encode() the resulting indices + palette -- the same encoder the
    indexed path uses.
    - JXL tier: scale to RGB888 and jxl_encode() it directly, skipping the
    indexed round-trip sst_emit_jxl() does.
    - no-graphics tier: nothing to draw, same as present().

    Supporting changes, all additive:

    - sst_scale_rgbx_to_rgb(): NN XRGB -> packed RGB888 scale helper, taking
    the source w/h as parameters (a truecolor source has no fixed
    SST_FB_W x SST_FB_H surface).
    - g_rgb_buf/g_rgb_cap: hoisted out of the WITH_JXL block so the sixel
    truecolor tier can reuse the shared RGB scratch in a no-libjxl build.
    - sst_image_rect_src(): the source-parameterized core of sst_image_rect,
    which becomes a thin SST_FB_W x SST_FB_H wrapper over it. Passing those
    two constants reproduces the wrapper's former behavior exactly (the
    source dims feed only the termgfx_geom_fit() call), so the indexed
    present()/mouse geometry is byte-identical.
    - sst_emit_jxl_rgb(): the tail of sst_emit_jxl() fed already-packed RGB.

    The indexed present() path is left byte-identical -- its dedupe /
    dirty-rect / retain machinery keys off the indexed g_last_fb surface and
    is deliberately not shared; the pacing / backpressure gates, which key
    off the tier-agnostic link state, are. A gated truecolor frame is dropped rather than retained (there is no rgbx tick()-retry buffer), since a
    truecolor source drives its own redraw cadence.

    Compile/link smoke check only: syncscumm links the new symbol into
    libtermgfx but does not call it yet (it stays on the indexed path). The functional unit test lands in the following task.

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

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