CHAR-PARTIAL-REDRAW: обязательная задача о неподвижном персонаже

Постановка пользователя: проверять, нужна ли отрисовка стража, когда он
не двигается.  Если движется — лишние ~150 000 тактов приемлемы: в
оригинале во время боя число физических кадров на логический тоже растёт
на единицу.

Замер чтением pop_cd из памяти машины показал, насколько цена
несоразмерна поводу:

  страж       x 257..284, y 18..56   28 x 39
  пламя (0,7) x 264..279, y  5..22   16 x 18
  пересечение x 264..279, y 18..22   16 x 5

То есть пламя задевает страже только макушку — 80 пикселей, — а
перерисовывается он целиком за 148 302 такта (85 524 спрайт с клинком и
снимком + 62 778 fore-проход), это 23 % работы кадра.  Пересечение при
этом настоящее: дело не в грубости маски меток, проверено числами.

В задаче записаны два варианта: A — частичная перерисовка только
пересечения (безопаснее, укладывается в контракт pop_cd), B — не рисовать
фон там, где он всё равно перекрыт неподвижным персонажем (дешевле, но
обрезанное пламя попадёт в ОЗУ-копию и heal вернёт дыру, когда персонаж
сдвинется).

Заодно уточнено, чем НЕ является P13 (вопрос пользователя): это не
перерисовка комнаты заново каждый кадр — такой вариант стоил бы порядка
3 000 000 тактов, семь растровых кадров, и оригинал так тоже не делает.
Разница в цене ПОСЕЩЕНИЯ тайла: у нас fore_tile сразу блитит, у оригинала
add_*table только кладёт запись, а рисует один draw_table в конце.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 15:35:54 +03:00
parent d3049693b8
commit a65da96960
2 changed files with 91 additions and 1 deletions
+54
View File
@@ -261,6 +261,60 @@ MEM-BANK2, MEM-BANK5, CLIP-1, KBD-1, DBG-CHEATS.
## P0 — делаем сейчас
### <a id="char-partial-redraw"></a>CHAR-PARTIAL-REDRAW. Неподвижный персонаж перерисовывается целиком из-за нескольких пикселей — ОБЯЗАТЕЛЬНО
**Постановка (пользователь, 2026-08-19).** Проверять, нужна ли отрисовка
стража, когда он НЕ ДВИГАЕТСЯ. Если движется — лишние ~150 000 тактов
приемлемы: в оригинале во время боя число физических кадров на логический
тоже растёт на единицу, и прийти к тому же решению не страшно.
**Измерено** (сцена 11/15, MAME, чтение `pop_cd` из памяти):
| | прямоугольник | размер |
|---|---|---|
| страж | x 257..284, y 18..56 | 28 × 39 |
| пламя правого факела (0,7) | x 264..279, y 5..22 | 16 × 18 |
| **пересечение** | **x 264..279, y 18..22** | **16 × 5** |
То есть пламя задевает страже только макушку — 80 пикселей, — а
перерисовывается он ЦЕЛИКОМ и стоит **148 302 такта** (85 524 сам спрайт с
клинком и снимком, 62 778 fore-проход). Это 23 % работы кадра.
Механика: `pop_torch_draw` запекает пламя в фон каждый кадр (`TORCH_ANIM_DIV
= 1`), `pop_cd_touch` метит область, `cd_quiet` видит пересечение с bbox
слота и снимает «тихий» бит — дальше `pop_char_draw` + `pop_char_fore`
идут полностью. Метка тут ни при чём: пересечение НАСТОЯЩЕЕ (проверено
числами выше, а не по грубой маске колонок).
**Варианты решения** (оба нуждаются в прототипе и замере):
- **A. Частичная перерисовка.** Если сигнатура слота не изменилась, но
фон задет — восстановить только пересечение: блит нужных колонок/строк
спрайта (`gfx_blit_cols_part_w` это умеет) и fore-проход только по
задетым тайлам. Ожидание: вместо 148 302 порядка 20 000.
Риск: надо аккуратно с клинком и брызгами (у них свой прямоугольник) и с
порядком слоёв внутри пересечения.
- **B. Не рисовать фон там, где он всё равно перекрыт.** Пламя обрезать по
прямоугольнику неподвижного персонажа — визуально результат тот же (эти
строки под ним и не видны), а персонажа не надо трогать вовсе:
экономия все 148 302. **Опасность:** обрезанное пламя попадает в
ОЗУ-копию, и когда персонаж сдвинется, `heal` вернёт фон С ДЫРОЙ.
Годится, только если запекать в копию полное пламя, а обрезать лишь
запись в видео-ОЗУ — то есть нужен блит с двумя разными масками.
**Порядок:** сначала A (безопаснее и укладывается в существующий контракт
`pop_cd`), B — только если A не хватит.
**Проверка:** замер 11/15 в ОБЕИХ позициях Кида (лёгкая x = 99 и тяжёлая
x = 106, разбор в [`../docs/perf_l11_room15.md`](../docs/perf_l11_room15.md)
§7) плюс визуальный прогон боя: персонаж не должен оставлять хвостов и
не должен просвечивать сквозь пламя.
**Место в очереди — [`../docs/perf_registry.md`](../docs/perf_registry.md),
позиция P15.** Смежное: P14 (fore-проход персонажа — вторая половина той же
цены).
### <a id="heal-width"></a>HEAL-WIDTH. Ширина точечных heal'ов не совпадает со следом перерисовки — ОБЯЗАТЕЛЬНО
**Постановка (пользователь, 2026-08-18).** Ширины heal'ов взяты «на глаз по