Падающие плиты: передний слой по пометкам, честные спрайты, замер кадра
Слой fore переведён на пометки ОБЪЕКТОВ вместо окна вокруг персонажа — порт set_redraw_fore/redraw_frames_fore (seg007:0550, seg008:214): pop_set_redraw_fore + pop_fore_needed + pop_fore_tile_b, пометки ставит падающий кусок вокруг себя (draw_mob, seg007:1147). Ключевая правка: пометки соседа считаются в ПРОХОДЕ ОТРИСОВКИ, а не в тике. Стояли в цикле тика — то есть по позиции ДО mob_tick_one, а кусок рисовался уже по новой; пока он летит внутри ряда, тайлы совпадают, но в кадр пересечения границы пометка указывала на прежний тайл и колонна кусок не перекрывала. Ровно один кадр, как и наблюдалось. Спрайты падающего куска: obj_id = 10 (add_mob_to_objtable, seg007:1170), части берутся по этому индексу — 70/74/72, а не 41/43/42 (плита В ПОКОЕ). Отсюда была «цельная ровная плита» вместо двух половин со сдвигом. Убрана подпорка «перерисовать соседний тайл поверх куска»: тащила на плиту чужой узор и окно и стоила по полной отрисовке тайла на кусок за кадр. Коридор heal сужен по высоте 32 -> 24 (реальный след спрайта 16 px). gfx_set_bank вынесен из потайлового цикла в обрамление прохода. Выяснено и зафиксировано: clip.right = 40 в add_mob_to_objtable — МЁРТВЫЕ данные. set_clip_rect вызывается под chtab_flip_clip[chtab_id], а для окружения флаг равен нулю — оригинал падающие куски не клипует вовсе. Портировать нечего; две попытки это сделать были ошибочны. Замер кадра (маркеры m1..m4, оставлены временно для проверки правок): покой 196 614 тактов (15,2 % кадра при периоде 1 290 000), во время падения гряды среднее 222 667, пик 1 428 990 — то есть 111 % кадра, шесть кадров подряд за пределом. Логика неизменна (88 020), растут фон (до 887 376) и спрайты (до 660 792). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -889,6 +889,24 @@ static void char_footprint(int obj_x, int obj_y, uint16_t w, uint16_t h,
|
|||||||
* obj_x — ЛОГИЧЕСКАЯ X кадра (до ×8/7), obj_y — низ спрайта, w/h — размер
|
* obj_x — ЛОГИЧЕСКАЯ X кадра (до ×8/7), obj_y — низ спрайта, w/h — размер
|
||||||
* кадра; всё остальное берётся из самого персонажа (ch). Окно fore-клипа к
|
* кадра; всё остальное берётся из самого персонажа (ch). Окно fore-клипа к
|
||||||
* этому моменту уже стоит: его задаёт тот, кто нарисовал спрайт. */
|
* этому моменту уже стоит: его задаёт тот, кто нарисовал спрайт. */
|
||||||
|
/* Передний слой ОДНОГО тайла — вход для прохода по пометкам
|
||||||
|
* (pop_fore_needed). Без окна fore-клипа: пометка уже сузила работу до
|
||||||
|
* нужных тайлов, а кусок тайла обязан лечь целиком — у оригинала foretable
|
||||||
|
* ничем не режется. */
|
||||||
|
void pop_fore_tile_b(int row, int col) __banked
|
||||||
|
{
|
||||||
|
uint8_t saved = pop_t_fclip_on;
|
||||||
|
pop_t_fclip_on = 0;
|
||||||
|
fore_tile(row, col);
|
||||||
|
pop_t_fclip_on = saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Банк на ВЕСЬ проход пометок, а не на каждый тайл: помеченных тайлов за
|
||||||
|
* кадр бывает больше десятка, и две смены банка на каждый — заметная доля
|
||||||
|
* прохода, который сам по себе дешёвый. */
|
||||||
|
void pop_fore_pass_begin(void) __banked { gfx_set_bank(GFX_BANK_SPRITE); }
|
||||||
|
void pop_fore_pass_end(void) __banked { gfx_set_bank(GFX_BANK_NORMAL); }
|
||||||
|
|
||||||
void pop_fore_over_char(const pop_char_t *ch, int obj_x, int obj_y,
|
void pop_fore_over_char(const pop_char_t *ch, int obj_x, int obj_y,
|
||||||
uint16_t w, uint16_t h) __banked
|
uint16_t w, uint16_t h) __banked
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -176,6 +176,11 @@ void pop_loose_mob_room_changed(void) __banked;
|
|||||||
* seg008:1561). Звать после отрисовки персонажей, перед fore-слоем. */
|
* seg008:1561). Звать после отрисовки персонажей, перед fore-слоем. */
|
||||||
/* Отрисовка падающих кусков, идущих ПОД Kid. Звать ПОСЛЕ pop_redraw_needed()
|
/* Отрисовка падающих кусков, идущих ПОД Kid. Звать ПОСЛЕ pop_redraw_needed()
|
||||||
* — фон кадра обязан быть готов до любого спрайта. */
|
* — фон кадра обязан быть готов до любого спрайта. */
|
||||||
|
/* Передний слой ОДНОГО тайла — зовёт pop_fore_needed (pop_redraw.c). */
|
||||||
|
void pop_fore_tile_b(int row, int col) __banked;
|
||||||
|
void pop_fore_pass_begin(void) __banked;
|
||||||
|
void pop_fore_pass_end(void) __banked;
|
||||||
|
|
||||||
void pop_loose_mob_draw(void) __banked;
|
void pop_loose_mob_draw(void) __banked;
|
||||||
void pop_loose_mob_draw_over(void) __banked;
|
void pop_loose_mob_draw_over(void) __banked;
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ static uint8_t rda_kind[NCOLS], rda_cnt[NCOLS];
|
|||||||
/* Сколько всего непустых пометок: без него проход по 40 ячейкам крутился бы
|
/* Сколько всего непустых пометок: без него проход по 40 ячейкам крутился бы
|
||||||
* КАЖДЫЙ кадр впустую (замер 2026-07-27 на прежнем rest-цикле: ~12 % кадра). */
|
* КАЖДЫЙ кадр впустую (замер 2026-07-27 на прежнем rest-цикле: ~12 % кадра). */
|
||||||
static uint8_t rd_pending;
|
static uint8_t rd_pending;
|
||||||
|
/* Пометки ПЕРЕДНЕГО слоя — однокадровые, отдельно от rd_*: те живут по
|
||||||
|
* страницам дабл-буфера (запекают фон), а эти транзиентны. */
|
||||||
|
static uint8_t rdf[NTILES];
|
||||||
|
static uint8_t rdf_pending;
|
||||||
|
|
||||||
void pop_redraw_reset(void) __banked
|
void pop_redraw_reset(void) __banked
|
||||||
{
|
{
|
||||||
@@ -25,6 +29,31 @@ void pop_redraw_reset(void) __banked
|
|||||||
for (i = 0; i < NTILES; i++) { rd_kind[i] = 0; rd_cnt[i] = 0; }
|
for (i = 0; i < NTILES; i++) { rd_kind[i] = 0; rd_cnt[i] = 0; }
|
||||||
for (i = 0; i < NCOLS; i++) { rda_kind[i] = 0; rda_cnt[i] = 0; }
|
for (i = 0; i < NCOLS; i++) { rda_kind[i] = 0; rda_cnt[i] = 0; }
|
||||||
rd_pending = 0;
|
rd_pending = 0;
|
||||||
|
for (i = 0; i < NTILES; i++) rdf[i] = 0;
|
||||||
|
pop_fore_pass_end();
|
||||||
|
rdf_pending = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_set_redraw_fore(uint8_t tilepos) __banked
|
||||||
|
{
|
||||||
|
if (tilepos >= NTILES) return;
|
||||||
|
if (!rdf[tilepos]) rdf_pending++;
|
||||||
|
rdf[tilepos] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Разбор пометок переднего слоя: тайлы обходятся в том же порядке, что и
|
||||||
|
* фон, и рисуются ПОСЛЕ всех объектов кадра — как foretable у оригинала
|
||||||
|
* (draw_tables, seg008:1373: back -> mid -> fore). */
|
||||||
|
void pop_fore_needed(void) __banked
|
||||||
|
{
|
||||||
|
uint8_t i, row = 0, col = 0;
|
||||||
|
if (!rdf_pending) return;
|
||||||
|
pop_fore_pass_begin();
|
||||||
|
for (i = 0; i < NTILES; i++) {
|
||||||
|
if (rdf[i]) { rdf[i] = 0; pop_fore_tile_b(row, col); }
|
||||||
|
if (++col == 10) { col = 0; row++; }
|
||||||
|
}
|
||||||
|
rdf_pending = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages) __banked
|
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages) __banked
|
||||||
|
|||||||
@@ -40,6 +40,17 @@
|
|||||||
* дабл-буфера перерисовать (1 = только текущая, 2 = обе). Повторная
|
* дабл-буфера перерисовать (1 = только текущая, 2 = обе). Повторная
|
||||||
* пометка перекрывает вид и берёт максимум счётчика. */
|
* пометка перекрывает вид и берёт максимум счётчика. */
|
||||||
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages) __banked;
|
void pop_set_redraw(uint8_t tilepos, uint8_t kind, uint8_t pages) __banked;
|
||||||
|
|
||||||
|
/* ПЕРЕДНИЙ СЛОЙ по пометкам — порт redraw_frames_fore/set_redraw_fore
|
||||||
|
* (seg007:0550). В оригинале эти пометки ставят ОБЪЕКТЫ, каждый вокруг
|
||||||
|
* себя: персонаж — прямоугольник футпринта (redraw_at_char, seg003:0576),
|
||||||
|
* падающий кусок — соседа справа и второй тайл на границе рядов (draw_mob,
|
||||||
|
* seg007:1147), анимация тайла — свой тайл (draw_trob). Пометка
|
||||||
|
* ОДНОКАДРОВАЯ: передний слой транзиентен, его снимает heal.
|
||||||
|
*
|
||||||
|
* Разбор (pop_fore_needed) звать ПОСЛЕ отрисовки всех объектов кадра. */
|
||||||
|
void pop_set_redraw_fore(uint8_t tilepos) __banked;
|
||||||
|
void pop_fore_needed(void) __banked;
|
||||||
void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages) __banked;
|
void pop_set_redraw_above(uint8_t col, uint8_t kind, uint8_t pages) __banked;
|
||||||
|
|
||||||
/* Разобрать пометки: нарисовать всё помеченное на ТЕКУЩЕЙ (back) странице и
|
/* Разобрать пометки: нарисовать всё помеченное на ТЕКУЩЕЙ (back) странице и
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "pop_tile.h" /* общие листья слоя фона (резидент): блит, тайлы, таблица */
|
#include "pop_tile.h" /* общие листья слоя фона (резидент): блит, тайлы, таблица */
|
||||||
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
|
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
|
||||||
#include "pop_state.h"
|
#include "pop_state.h"
|
||||||
|
#include "pop_redraw.h" /* пометки тайлов: сосед падающего куска (draw_mob) */
|
||||||
#include "pop_geom.h"
|
#include "pop_geom.h"
|
||||||
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
||||||
#include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев */
|
#include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев */
|
||||||
@@ -1165,6 +1166,30 @@ static void mob_tick_one(mob_t *m, uint8_t pg)
|
|||||||
*
|
*
|
||||||
* Порядок «кусок против Кида» здесь ни при чём — его решает defer выше, и там
|
* Порядок «кусок против Кида» здесь ни при чём — его решает defer выше, и там
|
||||||
* действует обычное правило. */
|
* действует обычное правило. */
|
||||||
|
/* Пометки СОСЕДА СПРАВА — порт draw_mob (seg007:1147). Оригинал каждый
|
||||||
|
* кадр помечает тайл col+1 в ряду куска сразу двумя пометками:
|
||||||
|
*
|
||||||
|
* set_redraw2(tilepos, 1); // фон соседа — рисуется ДО куска
|
||||||
|
* set_redraw_fore(tilepos, 1); // его передние части — ПОСЛЕ куска
|
||||||
|
*
|
||||||
|
* и повторяет их для второго ряда, если кусок висит на границе (ypos-18).
|
||||||
|
* Так правая часть куска (спрайт 72 лежит в столбце col+1) прячется за
|
||||||
|
* передней гранью соседнего пола, а передние части чужого тайла — колонна,
|
||||||
|
* например, — ложатся поверх куска.
|
||||||
|
*
|
||||||
|
* Здесь была подпорка: целый соседний тайл рисовался ПОВЕРХ куска прямо в
|
||||||
|
* mob_render. Она тащила на плиту чужой узор и окно и стоила по полной
|
||||||
|
* отрисовке тайла на кусок за кадр (MOB-CLIP-RIGHT). */
|
||||||
|
static void mob_mark_neighbour(const mob_t *m)
|
||||||
|
{
|
||||||
|
int8_t r = pop_y_to_row((int16_t)m->y);
|
||||||
|
int8_t rt = pop_y_to_row((int16_t)(m->y - 18));
|
||||||
|
int8_t c = (int8_t)(m->col + 1);
|
||||||
|
if (c > 9) return;
|
||||||
|
if (r >= 0 && r <= 2) pop_set_redraw_fore((uint8_t)(r * 10 + c));
|
||||||
|
if (rt != r && rt >= 0 && rt <= 2) pop_set_redraw_fore((uint8_t)(rt * 10 + c));
|
||||||
|
}
|
||||||
|
|
||||||
static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
||||||
{
|
{
|
||||||
uint8_t order[MOB_MAX], n = 0, i, j;
|
uint8_t order[MOB_MAX], n = 0, i, j;
|
||||||
@@ -1177,7 +1202,18 @@ static void mob_draw_pass(uint8_t pg, uint8_t want_defer)
|
|||||||
order[j] = i;
|
order[j] = i;
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
for (i = 0; i < n; i++) mob_render(&mobs[order[i]], pg);
|
for (i = 0; i < n; i++) {
|
||||||
|
/* Пометки соседа ставятся ЗДЕСЬ, а не в тике: у оригинала draw_mob
|
||||||
|
* (seg007:1147) считает ряд от той же координаты, по которой кусок
|
||||||
|
* рисуется. Стояли они в цикле тика — то есть по позиции ДО
|
||||||
|
* mob_tick_one, а рисовался кусок уже по новой. Пока он летит
|
||||||
|
* внутри ряда, старый и новый тайл совпадают и разницы не видно; но
|
||||||
|
* в кадр пересечения границы пометка указывала на прежний тайл, и
|
||||||
|
* передняя часть колонны кусок не перекрывала — ровно ОДИН кадр,
|
||||||
|
* как и наблюдалось (прогон 2026-08-13, комната 23, колонка 8). */
|
||||||
|
mob_mark_neighbour(&mobs[order[i]]);
|
||||||
|
mob_render(&mobs[order[i]], pg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop_loose_mob_tick(void) __banked
|
void pop_loose_mob_tick(void) __banked
|
||||||
|
|||||||
@@ -103,3 +103,13 @@ uint8_t pop_seamless;
|
|||||||
* КОМНАТЫ ОБЫЧНЫМ ХОДОМ и стартом уровня. */
|
* КОМНАТЫ ОБЫЧНЫМ ХОДОМ и стартом уровня. */
|
||||||
uint8_t pop_nav_hold;
|
uint8_t pop_nav_hold;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ВРЕМЕННО (замер фаз кадра 2026-08-13): четыре маркера-пустышки в
|
||||||
|
* РЕЗИДЕНТЕ. Брейкпоинт на каждом + printf totalcycles даёт длительность
|
||||||
|
* блоков: m1..m2 — логика (синий), m2..m3 — фон (зелёный), m3..m4 —
|
||||||
|
* спрайты (циан). В банк брейкпоинт ставить нельзя: 0xC000 общее окно. */
|
||||||
|
void pop_dbg_m1(void) { }
|
||||||
|
void pop_dbg_m2(void) { }
|
||||||
|
void pop_dbg_m3(void) { }
|
||||||
|
void pop_dbg_m4(void) { }
|
||||||
|
|||||||
@@ -75,3 +75,8 @@ void pop_dbg_trap(void);
|
|||||||
* Межбанковый: пишет pop_map, читает pop_map же, но через главный цикл. */
|
* Межбанковый: пишет pop_map, читает pop_map же, но через главный цикл. */
|
||||||
extern int8_t pop_jumped_mirror;
|
extern int8_t pop_jumped_mirror;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ВРЕМЕННО: маркеры фаз кадра (замер). */
|
||||||
|
void pop_dbg_m1(void); void pop_dbg_m2(void);
|
||||||
|
void pop_dbg_m3(void); void pop_dbg_m4(void);
|
||||||
|
|||||||
@@ -372,6 +372,7 @@ int main(void)
|
|||||||
pop_mirror_heal();
|
pop_mirror_heal();
|
||||||
pop_fore_heal(); /* + следы оверлея (шире прямоугольника Kid) */
|
pop_fore_heal(); /* + следы оверлея (шире прямоугольника Kid) */
|
||||||
PROF(2); /* логика (тот же синий) */
|
PROF(2); /* логика (тот же синий) */
|
||||||
|
pop_dbg_m1(); /* ЗАМЕР: начало логики */
|
||||||
kid_tick(); /* play_seq: следующий кадр */
|
kid_tick(); /* play_seq: следующий кадр */
|
||||||
pop_phys_tick(); /* K3: падение/приземление/стена */
|
pop_phys_tick(); /* K3: падение/приземление/стена */
|
||||||
pop_guard_tick(); /* логика стража — В БАНКЕ (guards.c) */
|
pop_guard_tick(); /* логика стража — В БАНКЕ (guards.c) */
|
||||||
@@ -447,6 +448,7 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
PROF(4); /* слой фона */
|
PROF(4); /* слой фона */
|
||||||
|
pop_dbg_m2(); /* ЗАМЕР: конец логики / начало фона */
|
||||||
|
|
||||||
pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */
|
pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */
|
||||||
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
||||||
@@ -613,6 +615,7 @@ int main(void)
|
|||||||
}
|
}
|
||||||
update_kid_render_dx(); /* straddle: смещение спрайта, если kid_room≠cur_room */
|
update_kid_render_dx(); /* straddle: смещение спрайта, если kid_room≠cur_room */
|
||||||
PROF(6); /* спрайты: страж, Kid, fore поверх */
|
PROF(6); /* спрайты: страж, Kid, fore поверх */
|
||||||
|
pop_dbg_m3(); /* ЗАМЕР: конец фона / начало спрайтов */
|
||||||
/* check_mirror (seg003:0798) — ПЕРВАЯ строка draw_people
|
/* check_mirror (seg003:0798) — ПЕРВАЯ строка draw_people
|
||||||
* (seg008:228A), до отрисовки кого бы то ни было: если Кид только что
|
* (seg008:228A), до отрисовки кого бы то ни было: если Кид только что
|
||||||
* пролетел сквозь зеркало, тень должна родиться ДО того, как слот
|
* пролетел сквозь зеркало, тень должна родиться ДО того, как слот
|
||||||
@@ -645,6 +648,10 @@ int main(void)
|
|||||||
if (pop_kid_hurt) pop_kid_hurt = 0;
|
if (pop_kid_hurt) pop_kid_hurt = 0;
|
||||||
}
|
}
|
||||||
pop_loose_mob_draw_over(); /* падающая плита НИЖЕ Kid → поверх него (y-порядок) */
|
pop_loose_mob_draw_over(); /* падающая плита НИЖЕ Kid → поверх него (y-порядок) */
|
||||||
|
/* ПЕРЕДНИЙ СЛОЙ по пометкам — последним в кадре, как foretable у
|
||||||
|
* оригинала (draw_tables, seg008:1373). Пометки ставят сами
|
||||||
|
* объекты вокруг себя (pop_redraw.h). */
|
||||||
|
pop_fore_needed();
|
||||||
pop_hp_draw(); /* полоса HP — только при изменении */
|
pop_hp_draw(); /* полоса HP — только при изменении */
|
||||||
PROF(6); /* fore поверх Kid + борта */
|
PROF(6); /* fore поверх Kid + борта */
|
||||||
/* Fore-слой Кида — В КОНЦЕ, после плиты и полосы HP: окно fore-клипа
|
/* Fore-слой Кида — В КОНЦЕ, после плиты и полосы HP: окно fore-клипа
|
||||||
@@ -673,6 +680,7 @@ int main(void)
|
|||||||
pop_dbg_room_label(cur_room); /* номер комнаты палочками — в банке */
|
pop_dbg_room_label(cur_room); /* номер комнаты палочками — в банке */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
pop_dbg_m4(); /* ЗАМЕР: конец спрайтов */
|
||||||
gfx_wait_vsync();
|
gfx_wait_vsync();
|
||||||
if (flash_on) { /* строб: цвет держался один кадр растра */
|
if (flash_on) { /* строб: цвет держался один кадр растра */
|
||||||
flash_bg(0, 0, 0);
|
flash_bg(0, 0, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user