diff --git a/applications/PoP/roomtest/pop_bg.h b/applications/PoP/roomtest/pop_bg.h index 0212c83..1f417c2 100644 --- a/applications/PoP/roomtest/pop_bg.h +++ b/applications/PoP/roomtest/pop_bg.h @@ -168,6 +168,11 @@ void pop_loose_mob_spawn_at(uint8_t room, int row, int col) __banked; void pop_loose_mob_tick(void) __banked; void pop_loose_mob_reset(void) __banked; /* убрать все куски (СТАРТ УРОВНЯ, mobs_count=0) */ +/* Забыть, на какой странице сделана первая запечка тайлов (см. bake_copy в + * pop_room.c). Звать при смене комнаты/уровня: номера тайлов повторяются, и + * первый же тайл с тем же номером получил бы копию вместо честной запечки. */ +void pop_bake_forget(void) __banked; + /* Смена комнаты: куски продолжают падать в СВОИХ комнатах (do_mobs крутит * mobs[] независимо от drawn_room), сбрасывается только heal-история. */ void pop_loose_mob_room_changed(void) __banked; diff --git a/applications/PoP/roomtest/pop_room.c b/applications/PoP/roomtest/pop_room.c index 013badd..5d4b711 100644 --- a/applications/PoP/roomtest/pop_room.c +++ b/applications/PoP/roomtest/pop_room.c @@ -26,6 +26,7 @@ #include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */ #include "pop_kid.h" /* Kid.curr_col/curr_row — порядок оверлеев */ #include "pop_cdraw.h" /* pop_cd — габарит кадра Кида (y-порядок плиты) */ +#include "pop_map.h" /* pop_upside — переворот (зелье инверсии) */ #include #include @@ -685,6 +686,54 @@ void pop_room_redraw_seam_left(uint8_t rows) __banked } } +/* ---- ЗАПЕЧКА НА ВТОРУЮ СТРАНИЦУ — копией, а не пересчётом ----------- * + * Точечные запечки ставятся с pages = 2, то есть срабатывают ДВА кадра подряд + * — по разу на каждую страницу дабл-буфера, — и оба раза считают одно и то же. + * А после первого раза нужный прямоугольник уже лежит в ОЗУ-копии первой + * страницы, и его можно просто скопировать: gfx_copy_page берёт источником + * ОЗУ-копию НЕактивной страницы (то есть ЧИСТЫЙ фон — спрайты рисуются банком + * без тени и в копию не попадают), а приёмник обновляет и в видео-ОЗУ, и в + * ОЗУ-копии. + * + * Замер 2026-08-17: полная запечка щебня — 179 914 такта, колодца — 138 318; + * копия прямоугольника 60x39 стоит ~30 000, а 64x9 — ~14 000. + * + * Слот на тайл помнит, НА КАКОЙ странице сделана первая запечка (+1; 0 = не + * было). Копируем только если первая была на ДРУГОЙ странице и дабл-буфер + * включён; иначе честно пересчитываем. Такая проверка выдерживает и + * переплетение двух запечек в одном кадре, и отключённый дабл-буфер (чит + * SPACE), и смену комнаты между кадрами. */ +static uint8_t bake_pg[30], bake_pg_above[10]; + +static uint8_t bake_copy(uint8_t *slot, int x, int ytop, int w, int h) +{ + uint8_t pg = (uint8_t)(gfx_get_draw_page() & 1); + gfx_rect_t r; + if (!*slot || (uint8_t)(*slot - 1) == pg || + gfx_get_draw_page() == gfx_get_visible_page()) { + *slot = (uint8_t)(pg + 1); /* это ПЕРВАЯ запечка */ + return 0; + } + *slot = 0; + if (pop_upside) ytop = POP_FLIP_TOP(ytop, h); /* копируем ЭКРАННЫЙ прямоугольник */ + r.x = (int16_t)x; r.y = (int16_t)ytop; + r.w = (uint16_t)w; r.h = (uint16_t)h; + gfx_copy_page(&r, GFX_COPY_DIRECT); + pop_cd_touch(x, ytop, w, h); /* область изменилась и на этой странице */ + return 1; +} + +/* Смена комнаты/уровня: запечки прошлой комнаты недоделанными не остаются + * (pop_trob_room_changed сбрасывает пометки), но слоты обнулить надо — иначе + * первый же тайл с тем же номером в новой комнате получит копию вместо + * честной запечки. */ +void pop_bake_forget(void) __banked +{ + uint8_t i; + for (i = 0; i < 30; i++) bake_pg[i] = 0; + for (i = 0; i < 10; i++) bake_pg_above[i] = 0; +} + /* ---- Плита-потолок (loose ряда 2 комнаты СВЕРХУ) ------------------- * * В полосе кладки у потолка (наш ряд −1) виден только НИЗ плиты * (draw_tile_aboveroom: bottom+loose, всё выше отрезано клипом POP_YOFF). @@ -728,6 +777,8 @@ void pop_ceil_shake_draw(int col) __banked void pop_ceil_bake_empty(int col) __banked { int x = POP_COL_XH[col] * 8; + /* Вторая страница — копией с первой (см. bake_copy). */ + if (bake_copy(&bake_pg_above[col], x, POP_YOFF, 64, CEIL_BAND_H + 1)) return; gfx_set_bank(GFX_BANK_NORMAL); /* Отдельного pop_cd_touch тут не надо: pop_bar_black метит сам, и ровно * этот же прямоугольник (было два вызова на одну область). */ @@ -864,6 +915,8 @@ void pop_floor_bake(int row, int col) __banked { int x = POP_COL_XH[col] * 8; int yb = POP_YOFF + 63 * row; + /* Вторая страница — копией с первой (см. bake_copy). */ + if (bake_copy(&bake_pg[row * 10 + col], x, yb + 26, 60, 39)) return; /* Пометку ставит сам pop_bar_black — по тому же прямоугольнику; отдельный * pop_cd_touch тут был вторым вызовом на одну область (4 502 такта). */ /* Wipe СВОЕЙ ячейки + правой грани (заходит в соседа) + перерисовка пола. diff --git a/applications/PoP/roomtest/roomtest_cold.c b/applications/PoP/roomtest/roomtest_cold.c index 3dac996..6d93a02 100644 --- a/applications/PoP/roomtest/roomtest_cold.c +++ b/applications/PoP/roomtest/roomtest_cold.c @@ -341,6 +341,7 @@ void enter_room_side(uint8_t room, uint8_t side) __banked Kid.room = room; pop_loose_reset(); /* loose-состояние не тянем из старой комнаты */ pop_trob_room_changed(); /* отложенные перерисовки пик — не из старой комнаты */ + pop_bake_forget(); /* и слоты «первая запечка была на странице N» */ pop_trob_anim_room(room); /* факелы/зелья: стартовая фаза + trob */ pop_start_chompers(room, Kid.curr_row); /* seg000:1288: чомперы РЯДА Кида */ pop_check_fall_flo(); /* спецсобытие ур.13: гряда плит сверху */