Files
Sprinter-SDCC/applications/PoP/roomtest/NEXT_SESSION.md
T
snark13 c0075c7754 NEXT_SESSION.md: op-блиты сделаны, вид тени отложен
Чтобы следующая сессия не начала задачу заново: библиотечная часть закрыта
(полный набор блочных AND/OR/XOR/NOT в libbgi, tests/accop 10/10), а вид
тени отложен по решению пользователя — со ссылкой на docs/shadow_render.md.
Исходная постановка оставлена ниже как справка.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 15:41:42 +03:00

13 KiB
Raw Blame History

Точка входа для следующей сессии (записано 2026-08-10, поздний вечер)

Файл для старта с чистого контекста: где всё стоит, что делать первым, какие грабли уже собраны. Читать целиком — он короткий. Дальше по ссылкам: TASKS_OPEN.md (доска), bug_list.md (открытые баги), CLAUDE.md.


1. Состояние репозитория

Всё закоммичено и запушено, main в синхроне с origin/main. Последний коммит сессии — 8beb66a.

tests-host: 5 наборов, все проходят ([geom] 3144). make size-check: чисто, роста нет.

Коммиты за день, по порядку:

хеш что
8cac51d убраны три последних /63 %4 в pop_room.c
72797e1 инвентаризация ВСЕХ делений по .asm, три убраны
8175121 scr_x таблицей на весь диапазон, включая отрицательные
fc0ede9 байтовая таблица x/7 вместо словарной (−1152 Б, на такт быстрее)
e261a35 замер в MAME: A/B со сборкой до правок, делений в горячем пути 0
67a4c71 BUG-TORCH-CHOMP-2: застывший чомпер накрывался пламенем
1b2111f L4-MIRROR шаги 1-2: зеркало в атласе + постановка тайла
844fa6d L4-MIRROR шаг 4: прыжок сквозь зеркало и рождение тени
8f0362f L4-MIRROR шаги 3 и 5 + левый клип колонок в libbgi
3913f1e fore-проход поверх отражения (ноги/голова вылезали из арки)
8beb66a заведён FORE-DUP с разбором

2. Состояние окружения

  • MAME запущена с образом уровня 4 (FIRST_LEVEL=4, PROF_BORDER=1). Пересобрать образ: make PROF_FLAGS="-DPROF_BORDER=1 -DFIRST_LEVEL=4" hdd, после этого MAME обязан полный рестарт (memory mame_hdd_rebuild_restart). Загрузка: keyseq d:{ENTER}, потом keyseq roomtest{ENTER}, ждать ~18 с.
  • SDLPoP пересобран с отладочной информацией (-O0 -g3). pkg-config на машине НЕТ, собирать так:
    cd applications/PoP/SDLPoP/src
    SDLC="-I/opt/homebrew/include -I/opt/homebrew/include/SDL2 -D_THREAD_SAFE"
    SDLL="-L/opt/homebrew/lib -lSDL2main -lSDL2 -Wl,-framework,Cocoa \
          -L/opt/homebrew/Cellar/sdl2_image/2.8.12_1/lib -lSDL2_image"
    make -j8 CFLAGS="-std=gnu99 -D_DARWIN_C_SOURCE -O0 -g3 $SDLC" LIBS="$SDLL"
    
    -std=c99 НЕ работает (прячет strncasecmp на Darwin), нужен gnu99.
  • НЕ ПРИБРАНО: в SDLPoP/src/seg008.c мой диагностический fprintf с меткой DBGMIRROR в начале add_objtable. Убрать перед следующей сборкой SDLPoP (или оставить — он гейтится по obj_type == 1 || == 4).

3. XOR/OR-блит через акселератор — СДЕЛАНО 2026-08-11, тень ОТЛОЖЕНА

Библиотечная часть закрыта. В libbgi поднят полный набор блочных операций акселератора — AND/OR/XOR/NOT, строками и колонками: gfx_blit_op / gfx_blit_part_op, gfx_blit_cols_op / gfx_blit_cols_part_wx_op (клип-окно и флип — как у копирующих близнецов); опкод операции патчится SMC, одна функция на все операции. putimage лишился попиксельного пути целиком (закрыт пункт 2d-1 docs/TODO.md). Регресс — tests/accop, 10/10 PASS в MAME, побайтно; tests/bgi_img получил две байтовые самопроверки. Механика и три ловушки — memory accel_block_ops.

Вид тени (два блиттера OR+XOR) отложен решением пользователя до того, как будут сделаны все уровни: пока тень рисуется обычной копией из атласов Кида. Причина не в примитивах — XOR несовместим с нашей прозрачностью #FF, а операция читает ОЗУ-копию экрана, из-за чего два прохода оригинала вырождаются в один XOR. Всё выясненное, замеры и четыре варианта — ../docs/shadow_render.md. Ключ к выбору варианта — список кадров, которыми тень реально пользуется (ожидание: бег, длинный прыжок из зеркала, питьё зелья, боёвка).

Ниже — исходная постановка задачи, оставлена как справка.

Что установлено (замером, не гипотезой). Тень уровня 4 в оригинале рисуется ДВУМЯ блитами одного и того же спрайта Кида (seg008:1602):

case 1: // shadow
    add_midtable(obj_chtab, obj_id + 1, obj_xh, obj_xl,     obj_y, blitters_2_or,  1);
    add_midtable(obj_chtab, obj_id + 1, obj_xh, obj_xl + 1, obj_y, blitters_3_xor, 1);

OR на месте, XOR со сдвигом на пиксель вправо — XOR гасит совпавшее, остаются края, отсюда «контурный» вид. Это ЗАМЫСЕЛ оригинала, не артефакт SDLPoP.

Подтверждено печатью из живого SDLPoP (DBGMIRROR): и тень, и отражение идут из chtab=2 (собственные спрайты Кида), swordbits=0, обычными кадрами:

type=4 chtab=2 img=40 dir=0 clipL=137 clipT=3 charid=0 frame=41   <- отражение
type=1 chtab=2 img=41 dir=0 clipL=137 clipT=3 charid=1 frame=42   <- тень

Различие между ними — ТОЛЬКО блиттер. Наша тень сейчас рисуется обычной прозрачной копией, то есть выглядит вторым Кидом.

Механизм на Sprinter (docs/part2/accelerator_doc.txt, memory sprinter_accelerator дополнена сегодня). Акселератор умеет блочные AND/OR/XOR; операцию задаёт ОПКОД CPU между триггерами:

LD A,(DE)    ; триггер чтения: блок из спрайта -> память акселератора
XOR (HL)     ; триггер операции: блок XOR с тем, что по адресу приёмника
LD (HL),A    ; триггер записи: результат обратно

Цена — «число байт / 7 МГц», попиксельного цикла CPU НЕТ. Операция ортогональна направлению: горизонтальный/вертикальный режим (LD L,L / LD A,A) выбирается отдельно и на операцию не влияет — то есть с нашими column-major спрайтами (accel_vertical_copy) это работает так же, как копия. Мнемоника: XOR (HL) даёт A = A ^ (HL); «xor (hl),a» на Z80 нет.

План

  1. Эксперимент в MAME на маленьком тесте в tests/, НЕ сразу в PoP. Примитив трогает ассемблерное ядро libbgi, проверять его надо в изоляции. Цель: убедиться, что связка read-триггер / XOR / запись даёт ожидаемый блок в вертикальном режиме.
  2. libbgi: _bgi_blit_cols_op_raw — клон _bgi_blit_cols_raw (asm), где write-триггер LD (DE),A заменён парой «XOR (dst) + LD (dst),A». Наружу — gfx_blit_cols_part_op(...) с параметром операции (COPY / OR / XOR), чтобы одним примитивом закрыть оба блиттера тени. Побочно закрывается давний пункт 2d-1 из docs/TODO.md (putimage с XOR/OR/AND_PUT до сих пор на попиксельном пути). После правки libbgi — make size-check ОБЯЗАТЕЛЕН.
  3. PoP: тень двумя блитами, OR на месте + XOR со сдвигом +1 по X. Место — ветка слота соперника в pop_char_draw (pop_cdraw.c), где уже стоит выбор атласа и клип тени по CHARID_1_SHADOW.
  4. Смотреть на палитру глазами. Тут предсказать нельзя: акселератор XOR-ит ИНДЕКСЫ, а SDLPoP делает XOR в 24-битном RGB (blit_xor, seg009:3190). DOS-оригинал (режим 13h) тоже XOR-ил индексы, то есть мы будем БЛИЖЕ к DOS, чем SDLPoP, но конкретные цвета контура определит раскладка нашей палитры (атласы перепакованы pop_pack_kid.py). Может выйти и лучше, и мусорнее — это надо увидеть.

4. Остальное открытое

  • FORE-DUP (bug_list.md) — передний слой тайла рисуется дважды при перекрытии объектов (Кид+отражение всегда, Кид+соперник — весь ближний бой). Картинку не портит, тратит такты. В оригинале невозможно: там redraw_at_char только ПОМЕЧАЕТ тайлы. Сначала замерить, потом чинить — окно клипа вместо перебора тайлов в своё время дало 3.2×.
  • TORCH-ANIM-RIGHT (bug_list.md) — под запечённым пламенем могут застыть не только челюсти чомпера, но и пики/меч/зелье справа от факела. На уровнях 1-4 такого соседства нет.
  • DIED-ON-BUTTON — не портирован died_on_button (seg007:776).
  • Долгие: BUG-SPIKE-1, BUG-CHOMP-JUMP-1 (оба низкий приоритет), L3-PASS, L3-COLOR, L1-SPEED, TUNE-1.
  • Не проверено в MAME из вчерашнего: отражение с fore-проходом и клип тени слева (собрано и залито, но живьём не смотрели).

5. Грабли, собранные сегодня

  • Не оценивать железо по своей же memory-заметке. Я заявил, что accel умеет только копирование и XOR потребует ~25 % кадра на CPU — неверно, поправил пользователь. Заметка описывала копирование, я принял её неполноту за свойство железа.
  • lldb через FIFO — плохая идея. Повторяющиеся -o при breakpoint command add записываются НЕПОЛНЫМИ (берётся последний), а оставшийся от неудачной попытки script print(... lldb.frame ...) уронил lldb прямо в обработчике точки останова. Три прыжка пользователя ушли впустую. Работает надёжно: добавить fprintf(stderr, ...) прямо в SDLPoP, пересобрать (он собирается за секунды) и читать stdout. В дереве уже есть такие метки (DBG kidobj).
  • make без hdd не обновляет образ MAME, а FIRST_LEVEL живёт в roomtest.c — при смене нужен touch roomtest.c. Я дважды сказал «образ пересобран», когда он не был.
  • Диапазон obj_x = 416..695 (посчитан из kid_data.bin: dx кадров Кида −5..+10, стража −2..+10, плюс render_dx ∈ {140,0,+140}). Пригодится всякий раз, когда нужна таблица по экранной X.