L9-INVERT II.4: персонажи рисуются перевёрнутыми (зеркальные страницы атласов)

Спрайты персонажей хранятся column-major (ради бесплатного H-флипа), а
вертикальное зеркало у такой раскладки — разворот байтов ВНУТРИ колонки,
чего accel не умеет.  Поэтому pop_vflip.c готовит зеркальные КОПИИ страниц
атласов: копия побайтово повторяет раскладку .atl (заголовок, каталог,
смещения лент), развёрнуты только пиксели — значит вызывающему достаточно
подменить номер страницы, которую он мапит в W0.

* Кэш ленивый (страница зеркалится при первом обращении в перевёрнутом
  виде) и живёт до смены уровня — зелье переключает состояние туда-обратно,
  перезеркаливать по 16 КБ на каждый переворот незачем.  EMM хватает: 34
  страницы из ~215 свободных.
* pop_cdraw/pop_kdraw: страница + позиция (top = 191 - obj_y для персонажа,
  192 - top - h для клинка).  «Пропустить skip строк сверху» у зеркальной
  ленты = «срезать снизу» у оригинала, поэтому клипы считаются как обычно.
* Модуль резидентный: он маппит W3 (приёмник копии) — банку так нельзя.
* pop_vflip_reset на смене уровня: копии сделаны из старых страниц.

Проверено в MAME: чит U переворачивает всё разом, Кид и факелы вверх ногами,
полоса HP на месте, бег без следов на фоне (heal бьёт в те же координаты).

ОСТАЁТСЯ (L9-CLIPCHAR): clip_char в перевороте должен резать снизу, а не
сверху — пока при pop_upside не режем вовсе.  Тени/брызг это не касается.
This commit is contained in:
2026-08-12 22:25:18 +03:00
parent 055d6d7c89
commit 755190674c
8 changed files with 216 additions and 6 deletions
+37
View File
@@ -0,0 +1,37 @@
/*
* pop_vflip.h — зеркальные по вертикали копии страниц атласов персонажей
* (зелье инверсии, уровень 9). Реализация и «почему постранично» —
* в pop_vflip.c.
*
* Кому нужно. Фон и все row-major спрайты переворачиваются даром (порядок
* строк = знак страйда, gfx_blit_*_vflip), а персонажи хранятся колонками —
* им нужен заранее развёрнутый набор пикселей. Отсюда правило вызывающего:
*
* страница = pop_upside ? pop_vflip_page(a->page) : a->page;
*
* и больше НИЧЕГО не меняется: смещения лент, размеры кадров, флип по
* горизонтали (знак страйда) остаются как были.
*
* Почему кэш не сбрасывается на каждом перевороте: зелье инверсии в
* оригинале переключает состояние туда-обратно (второе зелье, смерть Кида —
* seg000:1224), и держать 34 страницы EMM дешевле, чем перезеркаливать по
* 16 КБ при каждом переключении. Бюджет EMM это позволяет: свободно ~215
* страниц из 256 (memory sprinter_emm_budget). Освобождаем на смене
* уровня — вместе с самими атласами.
*/
#ifndef POP_VFLIP_H
#define POP_VFLIP_H
#include <stdint.h>
/* Номер страницы с ВЕРТИКАЛЬНО ЗЕРКАЛЬНОЙ копией атласа src. Первый вызов
* для страницы делает копию (~16 КБ побайтно — ощутимо, но однократно),
* дальше отдаёт из кэша. 0 — не хватило EMM-страниц (вызывающий должен
* нарисовать обычным атласом: лучше неперевёрнутый кадр, чем пустота). */
uint8_t pop_vflip_page(uint8_t src);
/* Освободить все копии (смена уровня). Атласы к этому моменту тоже
* перезагружаются, и старые копии стали бы мусором. */
void pop_vflip_reset(void);
#endif /* POP_VFLIP_H */