picopt — BMP to SCI0 picture converter
=======================================

Self-contained. Copy this whole folder to any Mac and run it; nothing to
install. The binary is universal (Intel + Apple Silicon) and links only
against macOS system frameworks. Requires macOS 12 or later.

The optional tools/ scripts need python3, which macOS provides (running one
may prompt you to install the Command Line Tools the first time).


CONVERT ONE PICTURE
-------------------

    ./picopt convert room.bmp pic.210

Output is a raw SCI0 picture resource. Import it into SCI Companion as a
raw resource -- do NOT use its "Import from bitmap".


CONVERT A WHOLE FOLDER
----------------------

    ./convert-all.sh /path/to/art /path/to/output


READING THE OUTPUT
------------------

    Conversion verifies OK          perfect
    ... (0.00%, 1/60800 px)         one stray pixel, invisible, fine
    *** TOO BIG ***                 must be fixed, see below

picopt exits non-zero on any pixel mismatch, even a harmless single pixel.
The file is still written correctly. Add -noverify if that bothers a script.


TWO HARD LIMITS -- BOTH FAIL SILENTLY IN THE GAME
-------------------------------------------------

1. Resources must stay under 65,536 bytes.
   SCI0 is 16-bit real mode and a resource lives in one segment. Over the
   limit nothing errors: the drawing commands are simply cut short and the
   room renders mostly white. picopt warns loudly -- believe it. No pic
   Sierra shipped in LSL4 exceeds this; their largest is 65,506.

2. Colour codes must stay below 40.
   picopt enforces this for you. Mentioned only so nobody "optimises" it
   away later: codes 40 and above render the wrong colour in isolated
   patches, which is maddening to diagnose.

If a picture comes out too big, the fix is in the art, not the settings --
fewer distinct regions and less fine dithering. See aseprite/.


DRAWING THE ART
---------------

Load aseprite/ega16.gpl as your palette: in the palette panel's options
menu choose Load Palette, then pick that file. It holds the 16 IBM EGA
colours SCI0 renders with.

Aseprite also has a built-in CGA palette with the identical 16 values
(verified byte-for-byte), if it shows in your presets -- it comes from a
bundled "Hardware Palettes" extension, so it is absent when that extension
is off, and its location moves between versions. Either is fine. Despite
the name, that CGA preset holds EGA values.

    aseprite/AUTHORING_GUIDE.md  read once before starting a picture

The single most important rule: draw in Indexed colour mode with that
palette loaded from the start. Converting an RGB piece to indexed afterwards lets
Aseprite pick its own palette and dither during the conversion, which bakes
noise permanently into the art and roughly doubles the output size.


OPTIONAL TOOLS
--------------

    python3 tools/check_complexity.py art.bmp
        Region count before converting. Thousands of single-pixel regions
        means stray pixels or leftover anti-aliasing.

    python3 tools/pic_report.py pic.210
        Where the bytes went: lines, fills, patterns, palette.

    python3 tools/check_preamble.py <files-or-dirs>
        Audits existing pic resources for the palette preamble. Pics without
        it can crash or lock up the game. Anything picopt produces is fine;
        this is for older or third-party files.

    python3 tools/render_pic.py pic.210 --compare art.bmp --png out.png
        Independent renderer, written from the format spec rather than
        reusing the converter's own code. Use it when a picture looks wrong
        and you want a second opinion that doesn't share picopt's
        assumptions.


A NOTE ON TESTING
-----------------

picopt's built-in verify renders with its own parser, so it cannot catch a
disagreement with the real interpreter -- a picture that rendered wrong
in-game once still reported "verifies OK" the whole time. Every real bug
found so far was found by running the room. Import and play it.
