PoP roomtest: clip_char (верхняя обрезка спрайта) + подстановка нажатой кнопки

Спуск Кида с кнопки (room8, кромка (0,6)) рисовался неверно: Кид просвечивал
в щель между кнопкой и ближним столбом, а ближняя рука была срезана до одного
оторванного пикселя.  Две независимые причины.

1. Не был портирован clip_char() (seg006:1749) — оригинал перед add_objtable
   обрезает спрайт персонажа сверху по y_clip[curr_row+1], когда тайл над
   головой стена или пол.  Порт: pop_clip_char_top() (pop_map.c, метрики по
   set_char_collision) + новый примитив gfx_blit_cols_part() в libbgi (блит
   column-major с пропуском skip верхних строк; обрезка сверху бесплатна —
   колонка непрерывна в ОЗУ, сдвигается только старт).  gfx_blit_cols стал
   тонкой обёрткой над ним.  kid_heal чистит уже ОБРЕЗАННЫЙ прямоугольник,
   иначе стирается кромка пола над срезом.

2. climb_overlay_tile (порт draw_floor_overlay, seg008:1E3A) выбирал ветку по
   СЫРОМУ коду тайла, а get_tile_to_draw (seg008:240) подменяет нажатую кнопку
   на floor/stuck.  Тайл-кнопка не проходил тест floor → уходил в
   draw_other_overlay, который кладёт поверх Кида ВЕСЬ тайл вместо узкой
   кромки floor_left_overlay[frame-137].  Фикс — tile_code_drawn(): одна
   подстановка на все слои (fore_only_tile/overlay_mid_tile перестали её
   дублировать, W3 −293 Б).

Проверено покадрово в MAME (шаг gv + снимок): кадры спуска 148..138 чистые,
после приземления на кнопке мусора нет.

Заодно: gfx_heal_noclip() (пара к gfx_blit_noclip; heal 11658 -> 8982 тактов)
и rest_pending в pop_trob — холостой проход по 30 тайлам только когда есть
отложенные редрои пик/кнопок (pop_process_trobs 89-111К -> 70-92К тактов).

START_ROOM временно = 8 (отладка спуска с кнопки), вернуть на 6/старт уровня.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 09:50:47 +03:00
parent c127a4b0d2
commit 6582154381
12 changed files with 369 additions and 62 deletions
+30
View File
@@ -0,0 +1,30 @@
/*
* gfx_heal_noclip — восстановить прямоугольник экрана из ОЗУ-копии БЕЗ
* клипа: вызывающий гарантирует, что прямоугольник целиком на экране,
* w,h ≤ 255. Быстрый вариант gfx_heal для тайловых движков (пара к
* gfx_blit_noclip).
*
* Зачем: gfx_heal идёт через общее ядро _gfx_heal_full (клип, нарезка
* полос >256, 16-битная арифметика) — замер в MAME (PoP roomtest,
* 2026-07-27): heal области 22×22 стоил 11 658 тактов при кадре 430 080,
* т.е. цена почти вся в обвязке, а не в пикселях. Линейное спрайтовое
* ядро _gfx_heal_sprite_noclip делает ту же работу без этого груза.
*
* Банк — как у gfx_heal: на время операции ВСЕГДА GFX_BANK_NORMAL
* (чтение отдаёт ОЗУ-копию, запись должна дойти и до ОЗУ), затем
* пользовательский банк восстанавливается. W3-скобка ставится ЗДЕСЬ:
* из модуля, собранного с --w3, её вызывать нельзя (после _bgi_begin
* окно W3 занято видеобанком и код вызывающего исчезает).
*/
#include "../_bgi.h"
void gfx_heal_noclip(int x, int y, uint8_t w, uint8_t h)
{
uint8_t saved = gfx_get_bank();
gfx_set_bank(GFX_BANK_NORMAL);
_bgi_begin();
_gfx_heal_sprite_noclip(x, y, w, h);
_bgi_end();
gfx_set_bank(saved);
}