Files
Sprinter-SDCC/applications/SprPoP/src/pop_vflip.h
T
snark13 31b82661eb SprPoP: автономное приложение, выделенное из roomtest
Порт PoP переехал в applications/SprPoP — приложение, которое собирается
само: код, оригинальные данные, конверторы ресурсов и сборка внутри одной
папки.  Наружу знает единственный путь — корень тулчейна (SPRINTER_ROOT,
по умолчанию ../..).  applications/PoP/roomtest ЗАМОРОЖЕНА и остаётся
архивом закрытых задач, багов и исполненных планов.

Скопировано из applications/PoP/roomtest@4b74478.  Перенос проверен
побайтово: собранный sprpop.exe совпал с roomtest.exe того же коммита,
все 39 дисковых ресурсов и все 16 генерируемых заголовков — тоже, host-
тесты зелёные (15/15).

Раскладка:
  src/           рукописный C (roomtest.c -> sprpop.c)
  gen/           генерируемые заголовки, в репозитории
  assets/orig/   оригинальные данные игры, вне репозитория (копирайт)
  assets/packed/ то, что ложится на диск, в раскладке диска
  tools/         конверторы; все пути — в одном tools/paths.py
  build/         выход: exe, каталоги ресурсов, hdd/, промежуточные atl/

Сборка ресурсов: assets/packed и gen — версионируемые ВХОДЫ, а не то, что
пересчитывается каждым make.  Автоматика построена на ОТСУТСТВИИ файла, а
не на таймстемпах: git не хранит времена, и в свежем клоне сравнение по
времени превращалось бы в лотерею.  Недостающий ресурс или заголовок
чинится сам, рекурсивным вызовом в ветку генерации.

Музыка собирается из любого из четырёх наборов записей (make music-mp3,
music-mt32, ...); набор входит в имя stamp'а, поэтому смена набора сама
делает музыку устаревшей.  Длины реплик больше не захардкожены: упаковщик
печатает их в gen/pop_music_ticks.h, и шкала сцены выражена через них —
иначе mt32 (реплики на 6% длиннее) молча ломал катсцену.

Тулчейн: в app.mk два обратносовместимых крючка (SRC_DIR/BUILD_DIR),
HDD_IMG стал ?=; команда сборки roomtest не изменилась.  Корневой
make host-tests переключён на SprPoP.

Подгонка тайминга катсцены с принцессой (PV_MAGIC_LEAD): сцена
render-bound и идёт ~49 тиков/с вместо 60, из-за чего кода реплики
приходила раньше молнии.  Это обход, а не лечение; разбор с замерами —
docs/BUGS_OPEN.md, записи SND-PACE-DEAD, PV-RENDER-BOUND, MUS-LEFT-TEAR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 12:12:28 +03:00

53 lines
3.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* pop_vflip.h — ВЕРТИКАЛЬНО ЗЕРКАЛЬНЫЕ наборы спрайтов персонажей
* (зелье инверсии, уровень 9). Реализация и замеры — в pop_vflip.c.
*
* Кому нужно. Фон и все row-major спрайты переворачиваются даром (порядок
* строк = знак страйда, gfx_blit_*_vflip), а персонажи лежат КОЛОНКАМИ —
* у них даром получается горизонтальное зеркало, а вертикальное требует
* развернуть байты внутри колонки. Такой набор готовит упаковщик
* (kid0_v.atl, sword_v.atl, g0_v.atl…), а здесь он только грузится и
* связывается с оригиналом. Правило вызывающего:
*
* страница = pop_upside ? pop_vflip_page(a->page) : a->page;
* if (!страница) страница = a->page; // набор не загружен
*
* Ни смещения лент, ни размеры кадров, ни горизонтальный флип при этом не
* меняются: зеркальный файл имеет ТУ ЖЕ раскладку, отличаются только пиксели.
*
* КОГДА ГРУЗИТЬ — на усмотрение приложения: pop_vflip_load_all можно звать
* где угодно (старт игры, показ интро, вход на уровень с зельем). До
* загрузки движок просто рисует неперевёрнутыми кадрами — это заметно, но
* не ломает ни кадр, ни физику.
*/
#ifndef POP_VFLIP_H
#define POP_VFLIP_H
#include <stdint.h>
#include <sprite.h>
/* Загрузить зеркальный файл path и связать его с атласом orig.
* 0 — OK, -1 — файла нет / не хватило EMM / таблица полна. */
int pop_vflip_add(const atlas_t *orig, const char *path);
/* То же, но зеркало УЖЕ загружено (например, прочитано из архива): таблица
* забирает его себе, и дальше он освобождается вместе с остальными. */
int pop_vflip_take(const atlas_t *orig, const atlas_t *mirror);
/* Страница-зеркало для страницы src; 0 — пары нет (набор не загружен). */
uint8_t pop_vflip_page(uint8_t src);
/* Загружен ли хоть один зеркальный атлас (чтобы не грузить дважды). */
uint8_t pop_vflip_ready(void);
/* Освободить весь набор (смена набора спрайтов соперника / уровня). */
void pop_vflip_reset(void);
/* Загрузить ВЕСЬ зеркальный набор: страницы Кида, меч и текущий набор
* соперника. Идемпотентна — повторный вызов ничего не делает. 0 — OK,
* -1 — что-то не загрузилось (движок останется на обычных кадрах).
* Живёт в банке 8 (pop_kboot.c): зовётся раз за игру/уровень. */
int pop_vflip_load_all(void) __banked;
#endif /* POP_VFLIP_H */