Замер цианной фазы: крупного лишнего в отрисовке персонажа нет
Циан 188 004 не двигался ни от P1, ни от P5, ни от P2b — разложил его зондами. Хорошая новость: Кид УЖЕ пропускается (204 такта на pop_char_draw), то есть надежда P3 сбылась после P1 — метка от чомпера до него больше не дотягивается. Страж же перерисовывается каждый кадр честно: пламя правого факела (0,7) рисуется в ячейке (0,8), где он стоит, и реально накрывает ему голову (пламя занимает y 5..22, страж 12..62). Отрисовка стража — 148 302: pop_char_fore (2 трамплина в банк 2 + обход тайлов) 62 778 42 % клинок (sword_draw + overlay_add + clip_add) 27 522 19 % блит спрайта + clip_char_right 20 982 14 % загрузка кадра и геометрия 12 696 9 % pop_clip_char_top (трамплин банк 4 -> банк 3) 8 658 6 % снимок прямоугольника + cd_clip_add 7 890 5 % gfx_w0_unmap + cd_sig_make 4 968 3 % вход + cd_heal 2 946 2 % Единственная явно лишняя статья — трамплин clip_char_top, и снять его непросто: функции нужны get_tile и таблицы деления из банка 3, перенос в резидент вернёт тот же трамплин внутрь. Остальное — работа, которую персонаж действительно делает. Зонды переставлены с уже закрытых замеров (loose_tick, физика) внутрь pop_cdraw; оснастка снимается позицией P12, когда оптимизация закончится. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -405,6 +405,44 @@ BUG-LATTICE-DOORTOP, BUG-SEAM-WEDGE-1) — только отдельным за
|
||||
|
||||
---
|
||||
|
||||
## 5б. Цианная фаза разложена [ЗАМЕР 2026-08-19]
|
||||
|
||||
Фаза 188 004 тактов, и она НЕ менялась ни от P1, ни от P5, ни от P2b.
|
||||
|
||||
| участок | такты |
|
||||
|---|---:|
|
||||
| `check_mirror` | 3 198 |
|
||||
| `loose_mob_draw` + `guard_over_kid` + `skip_mask` | **34 374** |
|
||||
| **`pop_char_draw(KID)`** | **204** |
|
||||
| **соперник: `char_draw` + `char_fore`** | **145 896** |
|
||||
| `fore_needed` + `hp_draw` | 2 598 |
|
||||
| `char_fore(KID)` + борта | 1 758 |
|
||||
|
||||
**Кид уже пропускается** — 204 такта, то есть надежда P3 всё-таки сбылась
|
||||
после P1: метка от чомпера до него больше не дотягивается. А страж
|
||||
перерисовывается каждый кадр, и это ЧЕСТНО: пламя правого факела (0,7)
|
||||
рисуется в ячейке (0,8), где он стоит, и реально накрывает ему голову
|
||||
(пламя занимает y 5..22, страж 12..62).
|
||||
|
||||
Отрисовка стража (148 302) по частям:
|
||||
|
||||
| участок | такты | доля |
|
||||
|---|---:|---:|
|
||||
| **`pop_char_fore`** (два трамплина в банк 2 + обход тайлов) | **62 778** | 42 % |
|
||||
| клинок: `pop_sword_draw` + `cd_overlay_add` + `cd_clip_add` | 27 522 | 19 % |
|
||||
| блит спрайта + `clip_char_right` | 20 982 | 14 % |
|
||||
| загрузка кадра и геометрия | 12 696 | 9 % |
|
||||
| **`pop_clip_char_top`** (трамплин банк 4 → банк 3) | 8 658 | 6 % |
|
||||
| снимок прямоугольника + `cd_clip_add` | 7 890 | 5 % |
|
||||
| `gfx_w0_unmap` + `cd_sig_make` | 4 968 | 3 % |
|
||||
| вход + `cd_heal` | 2 946 | 2 % |
|
||||
|
||||
**Вывод: крупного лишнего здесь нет.** Единственная явно лишняя статья —
|
||||
трамплин `clip_char_top` (8 658), и убрать его непросто: функции нужны
|
||||
`get_tile` и таблицы деления из банка 3, а перенос в резидент вернёт тот же
|
||||
трамплин внутрь. Всё остальное — работа, которую персонаж действительно
|
||||
делает: рисует себя, клинок и передний слой поверх себя.
|
||||
|
||||
## 6. Иерархия референсов (уточнена 2026-08-19)
|
||||
|
||||
Сравнение трёх реализаций луча видимости показало, что источники не
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "_pop_kdraw.h"
|
||||
#include "pop_vflip.h" /* зеркальные страницы атласов (зелье инверсии) */ /* меч + блит по id — сосед по банку 4 */ /* атласы/кадр Кида, pop_sword_draw, окна Char */
|
||||
#include "pop_cdraw.h"
|
||||
#include "pop_state.h" /* ВРЕМЕННО: зонды pop_dbg_b* */
|
||||
#include "pop_bg.h" /* POP_YOFF, pop_fore_over_char, pop_fore_set_clip */
|
||||
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
|
||||
#include "pop_map.h" /* hitp_curr/hitp_max — HP Кида; clip_char */
|
||||
@@ -503,6 +504,7 @@ void pop_char_draw(uint8_t who) __banked
|
||||
* сдвинул. Здесь прошлый кадр уже точно надо стереть. Если heal в этом
|
||||
* кадре был, вызов бесплатен: valid/ovalid уже сняты. */
|
||||
cd_heal(who);
|
||||
pop_dbg_b1(); /* ЗАМЕР: cd_heal сделан */
|
||||
|
||||
s->cw = 0; /* окно fore-клипа: пусто, пока не нарисовали */
|
||||
s->fpw = 0; /* габарит кадра: нечего перекрывать */
|
||||
@@ -633,7 +635,9 @@ void pop_char_draw(uint8_t who) __banked
|
||||
* так что «убрать последние bcut строк вывода» = «не рисовать
|
||||
* первые bcut строк оригинала», а это ровно то, что просит
|
||||
* clip_char. */
|
||||
pop_dbg_b2(); /* ЗАМЕР: кадр загружен, геометрия готова */
|
||||
ct = pop_clip_char_top(fp_x, obj_y, w, h);
|
||||
pop_dbg_b3(); /* ЗАМЕР: clip_char_top (трамплин банк 4->3) */
|
||||
if (!pop_upside) {
|
||||
if (ct > top) {
|
||||
skip = ct - top;
|
||||
@@ -691,6 +695,7 @@ void pop_char_draw(uint8_t who) __banked
|
||||
(uint8_t)(vis_w == w ? 0 : vis_w));
|
||||
} else rows = 0;
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
pop_dbg_b4(); /* ЗАМЕР: спрайт выведен */
|
||||
/* heal чистит ТОЛЬКО нарисованное: иначе стирается кромка пола над
|
||||
* срезом (мусор/дыра в кладке на второй странице дабл-буфера). */
|
||||
s->x[dp] = bx + lskip; s->y[dp] = top;
|
||||
@@ -700,6 +705,7 @@ void pop_char_draw(uint8_t who) __banked
|
||||
s->fpw = w; s->fph = h; /* габарит КАДРА (не обрезанный): */
|
||||
/* по нему считается футпринт */
|
||||
}
|
||||
pop_dbg_m15(); /* ЗАМЕР: снимок прямоугольника сделан */
|
||||
if (hurt) cd_splash(s, who, pages, fp_x, obj_y);
|
||||
/* add_sword_to_objtable (seg006:1798): клинок отдельным спрайтом поверх
|
||||
* персонажа — со своим прямоугольником heal. */
|
||||
@@ -710,6 +716,7 @@ void pop_char_draw(uint8_t who) __banked
|
||||
cd_clip_add(s, sx, sy, sw, sh);
|
||||
}
|
||||
}
|
||||
pop_dbg_m16(); /* ЗАМЕР: splash + клинок сделаны */
|
||||
gfx_w0_unmap();
|
||||
/* Что именно нарисовано на ЭТОЙ странице — снимок для пропуска
|
||||
* следующих кадров (DRAW-COST). Только если кадр РЕАЛЬНО рисовали:
|
||||
@@ -722,6 +729,7 @@ void pop_char_draw(uint8_t who) __banked
|
||||
* между ними (BUG-CHAR-STALE-PAGE). Без снимка слот просто не будет
|
||||
* «тихим», и следующий кадр начнётся с heal — старое сотрётся. */
|
||||
if (w && h) cd_sig_make(who, &cd_sig[who][dp]);
|
||||
pop_dbg_b5(); /* ЗАМЕР: pop_char_draw целиком */
|
||||
}
|
||||
|
||||
void pop_char_fore(uint8_t who) __banked
|
||||
@@ -738,6 +746,7 @@ void pop_char_fore(uint8_t who) __banked
|
||||
if (s->fpw)
|
||||
pop_fore_over_char(who == POP_CH_KID ? &Kid : &Guard,
|
||||
s->fpx, s->fpy, s->fpw, s->fph);
|
||||
pop_dbg_b6(); /* ЗАМЕР: pop_char_fore целиком */
|
||||
}
|
||||
|
||||
/* ---- ОТРАЖЕНИЕ В ЗЕРКАЛЕ (check_mirror, seg003:0798) ---------------- *
|
||||
|
||||
@@ -2776,11 +2776,8 @@ void pop_loose_tick(void) __banked
|
||||
}
|
||||
loose_any = found;
|
||||
}
|
||||
pop_dbg_m10(); /* ЗАМЕР: оба цикла по тайлам пройдены */
|
||||
pop_loose_mob_tick(); /* продвинуть+нарисовать падающий кусок (после тайлов) */
|
||||
pop_dbg_m11(); /* ЗАМЕР: pop_loose_mob_tick сделан */
|
||||
check_loose_fall_on_kid(); /* seg007:1192 — плита падает Киду на голову */
|
||||
pop_dbg_m12(); /* ЗАМЕР: check_loose_fall_on_kid сделан */
|
||||
/* Отложенная допечка ПРОШЛОГО приземления на вторую страницу — ПЕРЕД
|
||||
* разбором нового: иначе при двух плитах, севших подряд, land_bake
|
||||
* затирался новым и на одной странице оставался старый пол. */
|
||||
|
||||
@@ -365,7 +365,6 @@ int main(void)
|
||||
pop_check_skel(); /* спецсобытие ур.3: скелет встаёт */
|
||||
pop_check_mouse(); /* спецсобытие ур.8: мышь жмёт кнопку */
|
||||
pop_check_killed_shadow(); /* спецсобытие ур.12: смерть тени = смерть Кида */
|
||||
pop_dbg_b6(); /* ЗАМЕР: три спецсобытия уровней сделаны */
|
||||
pop_frame_timers(); /* timers (seg003:0735): вспышка слияния */
|
||||
pop_dbg_m9(); /* ЗАМЕР: pop_frame_timers сделан */
|
||||
pop_check_can_guard_see_kid(); /* луч видимости — ДО логики персонажей */
|
||||
@@ -375,32 +374,25 @@ int main(void)
|
||||
* тот на ней уже нарисован правильно: ни стирать, ни рисовать заново
|
||||
* не надо (DRAW-COST, контракт в pop_cdraw.h). Решение
|
||||
* перепроверяется перед самой отрисовкой — тик ещё впереди. */
|
||||
pop_dbg_m15(); /* ЗАМЕР: pop_ctrl_tick сделан */
|
||||
skip = pop_char_skip_mask();
|
||||
if (!(skip & 1)) pop_char_heal(POP_CH_KID); /* стереть прошлый кадр ЭТОЙ страницы */
|
||||
if (!(skip & 2)) pop_char_heal(POP_CH_OPP); /* и прошлый кадр соперника */
|
||||
/* Отражение в зеркале — свой heal: у него нет слота pop_cd и в
|
||||
* skip-маске он не участвует (рисуется/стирается безусловно, живёт
|
||||
* только пока Кид стоит на тайле зеркала). */
|
||||
pop_dbg_m16(); /* ЗАМЕР: heal обоих персонажей сделан */
|
||||
pop_mirror_heal();
|
||||
pop_fore_heal(); /* + следы оверлея (шире прямоугольника Kid) */
|
||||
PROF(2); /* логика (тот же синий) */
|
||||
pop_dbg_m1(); /* ЗАМЕР: начало логики */
|
||||
kid_tick(); /* play_seq: следующий кадр */
|
||||
pop_dbg_b1(); /* ЗАМЕР: kid_tick сделан */
|
||||
pop_phys_tick(); /* K3: падение/приземление/стена */
|
||||
pop_dbg_b2(); /* ЗАМЕР: pop_phys_tick сделан */
|
||||
pop_guard_tick(); /* логика стража — В БАНКЕ (guards.c) */
|
||||
pop_dbg_b3(); /* ЗАМЕР: pop_guard_tick сделан */
|
||||
pop_guard_phys_tick(); /* и его физика — та же, что у Кида (play_guard_frame) */
|
||||
/* Боёвка, порядок как в play_frame (seg000:872): сначала пометить
|
||||
* попадания с обеих сторон, потом применить, потом свести HP. */
|
||||
pop_dbg_b4(); /* ЗАМЕР: pop_guard_phys_tick сделан */
|
||||
pop_check_sword_hurting();
|
||||
pop_check_sword_hurt();
|
||||
pop_do_delta_hp();
|
||||
pop_dbg_b5(); /* ЗАМЕР: боёвка сделана */
|
||||
pop_guard_fallout(); /* страж провалился ниже комнаты — убрать (seg002:241) */
|
||||
if (pop_fell_out) { /* Kid пересёк нижнюю границу комнаты */
|
||||
uint8_t down = pop_room_link(cur_room, LINK_DOWN);
|
||||
@@ -647,6 +639,7 @@ int main(void)
|
||||
* фон кадра (перепечатки тайлов, шов) обязан быть готов ДО любого
|
||||
* спрайта, иначе перепечатка ложится поверх уже нарисованного куска —
|
||||
* так окно задней стены и передняя грань пола оказывались на плите. */
|
||||
pop_dbg_m10(); /* ЗАМЕР: check_mirror сделан */
|
||||
pop_loose_mob_draw();
|
||||
{ /* Кто позже — тот поверх; порядок задаёт обход тайлов, а не роль
|
||||
* персонажа (см. guard_over_kid). Отрисовка одна на всех Char
|
||||
@@ -659,6 +652,7 @@ int main(void)
|
||||
if (!g_after && !(skip & 2)) { pop_char_draw(POP_CH_OPP); pop_char_fore(POP_CH_OPP); }
|
||||
PROF(6); /* кадр Кида (тот же циан) */
|
||||
if (!(skip & 1)) pop_char_draw(POP_CH_KID); /* спрайт + брызги + клинок */
|
||||
pop_dbg_m11(); /* ЗАМЕР: Кид нарисован */
|
||||
#if DBG_KIDOBJ
|
||||
/* ВРЕМЕННО: трасса для сверки с SDLPoP кадр в кадр. Место — то
|
||||
* же, что у оригинала (конец add_kid_to_objtable), и ВНЕ skip:
|
||||
@@ -679,6 +673,7 @@ int main(void)
|
||||
/* ПЕРЕДНИЙ СЛОЙ по пометкам — последним в кадре, как foretable у
|
||||
* оригинала (draw_tables, seg008:1373). Пометки ставят сами
|
||||
* объекты вокруг себя (pop_redraw.h). */
|
||||
pop_dbg_m12(); /* ЗАМЕР: соперник + mob поверх сделаны */
|
||||
pop_fore_needed();
|
||||
pop_hp_draw(); /* полоса HP — только при изменении */
|
||||
PROF(6); /* fore поверх Kid + борта */
|
||||
|
||||
Reference in New Issue
Block a user