PoP: факелы и зелья (chtab_1) + быстрый блит фона gfx_blit_noclip

Графика chtab_1 (flame/sword/potion) — новый атлас pop_pot.atl:
- склянка зелья берётся из chtab_1 (seg008 draw_tile_fore: id 12 малая /
  13 большая при типах 2..4), а НЕ chtab_6 id 12 — res212 в VDUNGEON нет,
  каскад падал на VPALACE и рисовал кусок дворцовой декорации («мусорный
  объект» в комнате 5);
- пакуем chtab_1 целиком (id 1..23): пламя, склянки, кадры пузырька;
- MONO-блит (method_3_blit_mono, seg009:3040) красит спрайт цветом из
  ОБЩЕЙ 16-цветной палитры экрана — она добавлена в 0x30..0x3F, палитра
  chtab_1 в 0x40..0x4F; пузырёк пакуется силуэтом цвета 12 (красный),
  его маска — цвета 0;
- в env-атлас добавлено основание факела (env 146, seg008:489 — рисует
  правый сосед); в статический render_room оно не попадало.

Анимация (seg007 animate_torch/animate_potion + seg000:0B12
anim_tile_modif): при входе в комнату факелам и зельям задаётся случайная
стартовая фаза и заводится trob; факел — get_torch_frame, пламя в ячейке
ПРАВОГО соседа (xh = draw_xh+1, y = draw_main_y−40); зелье —
bubble_next_frame по младшим 3 битам модификатора (старшие 5 = тип, при
загрузке уровня modif <<= 3, seg009).  Пламя и пузырёк не запекаются в
фон: heal своей области + кадр поверх.  Скорость пламени /2 — наш
логический кадр короче игрового тика оригинала.

Скорость отрисовки (профиль в MAME, кадр = 430 080 тактов):
- замер показал, что цена блита почти НЕ зависит от размера — 13 288
  тактов на спрайт 32×3 против 4 617 у линейного спрайтового ядра без
  клипа; платим за проход gfx_blit → gfx_blit_part → _gfx_blit_full;
- в libbgi добавлен gfx_blit_noclip() — блит без клипа в ТЕКУЩЕМ банке
  (putsprite не годится: навязывает GFX_BANK_SPRITE, фону нужен
  TRANSPARENT ради ОЗУ-копии); pop_bg.blit_b уходит на него, когда
  спрайт целиком на экране и не нужен g_clip_top → ~2.9× на блит;
- W3-скобку ставит САМА libbgi: из модуля с --w3 её вызывать нельзя —
  после _bgi_begin окно W3 занято видеобанком и код вызывающего исчезает
  (проявлялось белым экраном);
- редрой шва больше не перерисовывает полосу потолка (bar начинается с
  POP_YOFF+3) — это удваивало стоимость блока при анимации решётки;
- docs/size_optimization_plan.md §7–§8: замеры, сделанное и запас
  (батчинг W3-скобки, решётка одним спрайтом, лишние блиты).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 20:53:04 +03:00
parent 63a3b60524
commit c127a4b0d2
16 changed files with 377 additions and 16 deletions
@@ -289,3 +289,47 @@ Kid, обычно 2–4 за кадр) рисовал ещё и `bottom_id` —
`redraw_frames_above`; сузить до колонок, реально задетых спрайтом.
6. `wall_pattern` внутри fore/overlay — тяжёлая (PRNG + до 4 блитов); проверить,
не зовём ли её там, где оригинал ограничивается `wall_fram_main`.
---
## 8. Скорость отрисовки: замеры и запас (2026-07-27)
Профилирование в MAME (маркеры в порт 0xFE + `wpiset … totalcycles`, приём из
memory `mame_mcp_bridge`). Кадр Sprinter = **430 080 тактов**.
**Стоимость блита почти НЕ зависит от размера** — платим за проход по цепочке
`gfx_blit → gfx_blit_part → _gfx_blit_full` (16-битная арифметика, клип,
пересчёт src, нарезка полос >256), а не за пиксели:
| путь (спрайт 32×3) | тактов |
|---|---|
| `gfx_blit` (общее ядро, с клипом) | 13 288 |
| линейное спрайтовое ядро без клипа (`putsprite` при `gfx_sprite_clip(0)`) | 4 617 |
Отсюда `draw_tile(0,0)` тайла шва (9 блитов) стоил **183 690 тактов = 43 %
кадра**; сам `bar` — только 13 308.
**СДЕЛАНО (шаг 1):** в libbgi добавлен `gfx_blit_noclip()`
(`common/gfx_blit_noclip.c`, прототип в `include/gfx.h`) — блит без клипа в
ТЕКУЩЕМ банке через линейное ядро; `pop_bg.blit_b` уходит на него, когда
спрайт целиком на экране и не нужен `g_clip_top`. Выигрыш ~2.9× на каждом
фоновом блите (подтверждено в MAME).
**ВАЖНО:** W3-скобку (`_bgi_begin/_bgi_end`) ставит САМА libbgi — вызывать её
из модуля, собранного с `--w3`, нельзя: после `_bgi_begin` окно W3 занято
видеобанком и код вызывающего исчезает из адресного пространства (проверено:
белый экран).
**ЗАПАС (шаг 2), когда перестанет хватать бюджета кадра:**
1. **Батчинг W3-скобки** — одна `_bgi_begin/_bgi_end` на весь `draw_tile`
вместо скобки на блит; нужен публичный batch-API в libbgi (как у
спрайтового движка). Осторожно: между begin/end стоит `DI` — длинная
серия задержит кадровое прерывание.
2. **Решётка ворот одним спрайтом** — `draw_gate_back` рисует бары по одному
(`env 52`, до 7 блитов). Сгенерировать в атласе «столб решётки» (повтор
бара на высоту тайла) и выводить одним `gfx_blit_part` с обрезкой по фазе
`gate_bot_y & 7`: 7 блитов → 1.
3. **Не перерисовывать статичные части шва** — грань ворот (env 47, 26×62),
пол (41) и кромка (43) при анимации решётки не меняются; если стирать
только полосу баров, уйдут ещё 3 блита из 9.
4. См. также §7 (лишние блиты, которых нет в оригинале).