P1: чомпер перерисовывался неизменной позой — минус 110 802 такта

Позиция заводилась с НЕПОЛНЫМ диагнозом.  Я приписал 190 260 тактов
пометке от факела (пламя лежит в ячейке правого соседа, то есть поверх
чомпера, и запекается каждый кадр).  Правка по этому диагнозу не дала
ничего: 769 002 против 768 684.

Зонд pop_dbg_kind показал факт: все 312 перерисовок прогона — вид
POP_RD_CHOMP, полная, и ни одной от факела.  Собственная пометка чомпера
просто перебивала пометку соседа.

Настоящая причина нашлась сверкой с animate_chomper (seg007:0448).
Оригинал заканчивает её так:

    if ((curr_modifier & 0x7F) < 6) redraw_at_trob();

то есть перерисовывает чомпер только пока фаза меньше 6 — пять кадров из
пятнадцати.  Это не оптимизация оригинала, а следствие таблицы поз:
chomper_fram1 = {3,2,0,1,4,3,3}, и с фазы 5 до конца круга поза одна и та
же.  Мы метили тайл каждый кадр, пока trob жив, а живёт он всё время, пока
Кид в том же ряду — то есть платили полный draw_tile плюс heal 32x64 за
неизменную картинку в двух третях кадров.

Сделано:

  1. пометка только при фазе < 6; на фазе 5 — обе страницы дабл-буфера
     (она последняя рисуемая, её поза обязана лечь на обе; вторую страницу
     пометка догоняет в кадре фазы 6, где поза та же — CHOMP_FRAM1[6] == 3);
  2. новый вид POP_RD_CHOMP_ANIM -> pop_chomp_anim_draw: три блита графики
     чомпера поверх свежего пламени, без heal и без остальных слоёв — порт
     ветки redraw_frames_anim (seg008:0211), где оригинал делает ровно
     draw_tile_anim_topright / draw_tile_anim_right / draw_tile_anim и
     никакого wipe;
  3. приоритет полной перерисовки над anim в pop_set_redraw: у оригинала
     это два независимых счётчика и full побеждает, а у нас вид один на
     тайл, и без проверки исход решал бы порядок trob'ов в списке.

Обе половины работают — замер даёт 40 % полных перерисовок и 60 % лёгких.
Работа 768 684 -> 657 882 (медиана), зелёная 294 510 -> 183 420.  В 40 %
кадров цена прежняя: там поза реально меняется, это честная работа.

Циан не сдвинулся ни на такт, то есть надежда P3 (Кид перестанет будиться
каждый кадр) пока не оправдалась — метки продолжают его будить.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 11:30:01 +03:00
parent f81b30eb68
commit de68eb5cec
7 changed files with 198 additions and 20 deletions
+41
View File
@@ -626,6 +626,47 @@ void pop_loose_shake_draw(int row, int col) __banked
gfx_set_bank(GFX_BANK_NORMAL);
}
/* Вернуть ТОЛЬКО слой anim чомпера — порт ветки redraw_frames_anim в
* redraw_needed (seg008:0211). Контракт и разбор — в шапке объявления
* (pop_bg.h).
*
* Чем это отличается от pop_chomp_redraw и почему нужна отдельная функция.
* Пометку ставит АНИМАЦИЯ ФАКЕЛА: пламя лежит в ячейке ПРАВОГО соседа
* (seg008:560), то есть поверх чомпера, и запекается в фон каждый кадр.
* Возвращать после него надо ровно графику чомпера — а pop_chomp_redraw
* делал heal 32x64 плюс ПОЛНЫЙ draw_tile, то есть пересобирал тайл со всеми
* слоями (правая грань, база, низ, loose), которых пламя не касалось.
* Замер 11/15 (2026-08-19): 190 260 тактов на этот единственный тайл, 24 %
* работы кадра.
*
* heal не нужен: поза чомпера здесь НЕ меняется (свою анимацию ведёт
* pop_chomp_redraw по своей пометке), стирать нечего — рисуем ту же
* графику поверх свежего пламени. Оригинал на пометку anim wipe тоже не
* делает: у него это отдельный счётчик wipe_frames.
*
* Передний слой (зубья, POP_CHOMP_FRAM_FOR) сюда НЕ входит — как и в
* оригинале, где fore идёт по своему счётчику redraw_frames_fore. Геометрия
* это подтверждает: пламя занимает 18 строк с низом на 63*row+22, передние
* зубья — на dmy = 63*row+62, то есть на 40 строк ниже; пересекается с огнём
* только ВЕРХНЯЯ челюсть (подъём до 0x32 = 50 px), а она в back-слое. */
void pop_chomp_anim_draw(int row, int col) __banked
{
int x = POP_COL_XH[col] * 8;
int dmy = 63 * row + 62; /* dby - 3, как в draw_tile */
uint8_t cm = pop_tile_mod(row, col);
uint8_t pose = pop_chomp_pose(cm);
gfx_set_bank(GFX_BANK_SPRITE);
pop_cd_batch_begin(); /* одна пометка на все куски */
pop_env_b(CHOMP_FRAM_BOT[pose], x, dmy);
if (cm & 0x80) /* кого-то перемололо */
pop_env_b((uint8_t)(pose + 114), x + 8, dmy - 6);
if (CHOMP_FRAM_TOP[pose])
pop_env_b(CHOMP_FRAM_TOP[pose], x, dmy - CHOMP_FRAM_Y[pose]);
pop_cd_batch_end();
gfx_set_bank(GFX_BANK_NORMAL);
}
/* Перерисовать пики тайла (row,col) на back-странице по ЖИВОМУ modif
* (pop_trob). Кадр выдвижения рисует ПРАВЫЙ сосед (draw_tile ветка lcode==2
* читает lmod = pop_t_bg[row*10+col] = живой modif пики). pop_t_bg должен указывать