CLIP-1: heal Кида и стража — линейным ядром, когда клип не нужен
kid_heal/pop_guard_heal звали gfx_heal всегда, хотя рисуют ровно тот прямоугольник, который блит в большинстве кадров кладёт noclip-ядром. Все три места heal (+ heal_off фона) сведены к общему pop_heal_fast. Замер в MAME, счётчики totalcycles на входах kid_heal и kid_tick (вся группа heal за кадр), комната 1, Кид стоит: клипающее ядро 26 200 тактов/кадр (149 кадров) noclip 15 848 тактов/кадр (239 кадров) −10 352 такта, −39.5 %. A/B в одном прогоне: вторая половина снята с пропатченным в памяти условием (jr nz → jr), то есть на той же геометрии. Размер СУММАРНО −362 Б: _CODE +17, BANK2 −116 (свободно 2708 — это тесный банк из рисков levels_plan §5), BANK3 −263, BANK4 без изменений. Грабли по дороге: первым заходом хелпер был static inline в pop_bg.h — SDCC 4.5 И встраивает тело (181 Б) в каждый вызов, И оставляет копию в каждом TU, который видит заголовок. pop_guard_heal раздулся с ~60 до 663 Б, итого +1091 Б в _CODE и +636 Б в банке стража. Отсюда pop_draw.c: обычная функция в резиденте W1, из банков это прямой call без трамплина. pop_room_clip_borders оставлен клипающим осознанно (320 не лезет в 8 бит, гейт border_dirty редкий) — причина записана в коде. Проверено визуально: ходьба, прыжок, спуск, позиция за решёткой шва (straddle — там работает клипающий фолбэк) — артефактов нет. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -78,7 +78,9 @@ drawn_room с `curr_col=-1/10` + снапшоты соседей `g_lcol/g_rcol`
|
|||||||
### S4. Полировка
|
### S4. Полировка
|
||||||
- Окклюзия/ceiling у шва при straddle, BUG-OCCL-1 (глубина), правый край.
|
- Окклюзия/ceiling у шва при straddle, BUG-OCCL-1 (глубина), правый край.
|
||||||
|
|
||||||
## Связанные баги (`../roomtest/bug_list.md` — все открыты)
|
## Связанные баги — все ЗАКРЫТЫ (`../roomtest/bug_closed.md`)
|
||||||
BUG-CEIL-1 (руки при прыжке вверх), BUG-CEIL-2 (loose в потолке),
|
BUG-CEIL-1 (руки при прыжке вверх), BUG-CEIL-2 (loose в потолке),
|
||||||
BUG-CEIL-3 (потолок над анимируемыми воротами), BUG-OCCL-1 (тень дальней
|
BUG-CEIL-3 (потолок над анимируемыми воротами), BUG-OCCL-1 (тень дальней
|
||||||
колонны). Memory: `pop_seam_room_model`.
|
колонны) — починены без полной straddle-модели. То есть S4 «полировка
|
||||||
|
окклюзии» осталась актуальной только для окклюзии У ШВА при straddle.
|
||||||
|
Memory: `pop_seam_room_model`.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ EXTRA_FLAGS ?= --gfx 256 --bank 2=pop_bg.c --bank 4=pop_gdraw.c --bank 3=pop_map
|
|||||||
# MAME = время фазы в растровых строках.
|
# MAME = время фазы в растровых строках.
|
||||||
PROF ?= 1
|
PROF ?= 1
|
||||||
PROF_FLAGS := -DPROF_BORDER=$(PROF)
|
PROF_FLAGS := -DPROF_BORDER=$(PROF)
|
||||||
EXTRA_SRCS := pop_state.c pop_kid.c pop_ctrl.c pop_level.c pop_trob.c pop_redraw.c pop_geom.c pop_guard.c
|
EXTRA_SRCS := pop_state.c pop_draw.c pop_kid.c pop_ctrl.c pop_level.c pop_trob.c pop_redraw.c pop_geom.c pop_guard.c
|
||||||
|
|
||||||
BG_DIR := $(CURDIR)/../poc/res/bg
|
BG_DIR := $(CURDIR)/../poc/res/bg
|
||||||
KID_DIR := $(CURDIR)/../poc/res/kid
|
KID_DIR := $(CURDIR)/../poc/res/kid
|
||||||
@@ -71,4 +71,4 @@ $(KID_DATA): $(TC)/pop_pack_kid.py $(TC)/pop_pack_bg.py
|
|||||||
kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py
|
kid_data.h $(KID_BIN): $(TC)/pop_extract_kid_data.py
|
||||||
cd $(TC) && python3 pop_extract_kid_data.py
|
cd $(TC) && python3 pop_extract_kid_data.py
|
||||||
|
|
||||||
$(EXAMPLE).exe: guards.c pop_guard.c pop_guard.h pop_gdraw.c pop_state.c pop_state.h pop_cheat.h pop_bg.c pop_bg.h pop_geom.c pop_geom.h pop_redraw.c pop_redraw.h pop_kid.c pop_kid.h pop_ctrl.c pop_ctrl.h pop_map.c pop_map.h pop_level.c pop_level.h pop_trob.c pop_trob.h kid_data.h $(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)
|
$(EXAMPLE).exe: guards.c pop_guard.c pop_guard.h pop_gdraw.c pop_draw.c _pop_draw.h pop_state.c pop_state.h pop_cheat.h pop_bg.c pop_bg.h pop_geom.c pop_geom.h pop_redraw.c pop_redraw.h pop_kid.c pop_kid.h pop_ctrl.c pop_ctrl.h pop_map.c pop_map.h pop_level.c pop_level.h pop_trob.c pop_trob.h kid_data.h $(BG_DATA) $(KID_DATA) $(KID_BIN) $(LVL_DATA)
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
а то, **что берём в работу сейчас и в каком порядке**. Каждая запись: что
|
а то, **что берём в работу сейчас и в каком порядке**. Каждая запись: что
|
||||||
сделать, почему именно сейчас, чем подтверждать результат.
|
сделать, почему именно сейчас, чем подтверждать результат.
|
||||||
|
|
||||||
**Открытые баги** (все Medium/косметика, Critical'ов нет):
|
**Открытых багов нет** (ревизия 2026-08-01): в [`bug_list.md`](bug_list.md)
|
||||||
[BUG-CEIL-1](bug_list.md#bug-ceil-1) · [BUG-CEIL-3](bug_list.md#bug-ceil-3) ·
|
остались только незакрытые оптимизации [T-1](bug_list.md#t-1),
|
||||||
[BUG-OCCL-1](bug_list.md#bug-occl-1) ·
|
[T-2](bug_list.md#t-2) и незаконченная
|
||||||
[BUG-CEIL-2](bug_list.md#bug-ceil-2) (отложен) ·
|
[таблица обхода 24 комнат](bug_list.md#обход-всех-24-комнат-уровня-1).
|
||||||
оптимизации [T-1](bug_list.md#t-1), [T-2](bug_list.md#t-2).
|
Следующая порция багов придёт оттуда и из L1-PASS.
|
||||||
|
|
||||||
Правило проекта в силе: механику сверять с `../SDLPoP/src/` ДО кодинга;
|
Правило проекта в силе: механику сверять с `../SDLPoP/src/` ДО кодинга;
|
||||||
диагноз платформы подтверждать артефактом (брейкпоинт/дамп/.asm), а не
|
диагноз платформы подтверждать артефактом (брейкпоинт/дамп/.asm), а не
|
||||||
@@ -20,7 +20,8 @@
|
|||||||
|
|
||||||
## P0 — делаем сейчас
|
## P0 — делаем сейчас
|
||||||
|
|
||||||
*(KBD-1 закрыт до финальной полировки — см. ниже; следующая в работе — CLIP-1.)*
|
*(KBD-1 закрыт до финальной полировки, CLIP-1 сделан — оба ниже. P0 пуст;
|
||||||
|
следующая в работе — P1, начиная с L1-START/L1-EXIT.)*
|
||||||
|
|
||||||
### KBD-1. Shift + стрелки: нажатия теряются — **ПРИЧИНА НАЙДЕНА, ФИКС ПРОВЕРЕН**
|
### KBD-1. Shift + стрелки: нажатия теряются — **ПРИЧИНА НАЙДЕНА, ФИКС ПРОВЕРЕН**
|
||||||
|
|
||||||
@@ -284,7 +285,43 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### CLIP-1. Аудит блитов: где клип не нужен
|
### CLIP-1. Аудит блитов: где клип не нужен — **СДЕЛАНО 2026-08-01**
|
||||||
|
|
||||||
|
> **Итог.** Heal Кида и стража переведены на выбор ядра по тому же тесту,
|
||||||
|
> что давно стоит у блитов. Замер в MAME (счётчики `totalcycles` на входах
|
||||||
|
> `kid_heal` и `kid_tick`, то есть вся группа heal за кадр; комната 1, Кид
|
||||||
|
> стоит, стража нет):
|
||||||
|
>
|
||||||
|
> | путь | тактов на кадр | кадров в выборке |
|
||||||
|
> |------|----------------|------------------|
|
||||||
|
> | клипающее ядро (как было) | **26 200** | 149 |
|
||||||
|
> | noclip (стало) | **15 848** | 239 |
|
||||||
|
>
|
||||||
|
> **−10 352 такта на кадр, то есть −39.5 % с группы heal** (≈0.49 мс при
|
||||||
|
> ~21 МГц). A/B честный: оба замера сняты в ОДНОМ прогоне, вторая половина —
|
||||||
|
> с пропатченным в памяти условием (`jr nz` → `jr` в `pop_heal_fast`), то
|
||||||
|
> есть на той же геометрии и в той же сцене.
|
||||||
|
>
|
||||||
|
> **Размер: −362 Б суммарно** (не плюс!): `_CODE` 25 289 → 25 306 (+17),
|
||||||
|
> BANK2 13 792 → **13 676** (−116, свободно стало 2708 Б — это тот самый
|
||||||
|
> тесный банк из рисков `levels_plan.md` §5), BANK3 6512 → 6249 (−263),
|
||||||
|
> BANK4 без изменений.
|
||||||
|
>
|
||||||
|
> **Грабли, стоившие двух пересборок** (вынесено в память
|
||||||
|
> `sdcc-static-inline-double-cost`): первым заходом хелпер был `static
|
||||||
|
> inline` в `pop_bg.h` — и SDCC 4.5 И встроил его тело (181 Б) в каждое
|
||||||
|
> место вызова, И оставил отдельную копию в КАЖДОМ TU, который видит
|
||||||
|
> заголовок. `pop_guard_heal` раздулся с ~60 до 663 Б, итого +1091 Б в
|
||||||
|
> `_CODE` и +636 Б в банке стража. Лечится обычной функцией в одном
|
||||||
|
> резидентном модуле (`pop_draw.c`, W1 — из банков это прямой `call` без
|
||||||
|
> трамплина, как у `pop_sword_draw`).
|
||||||
|
>
|
||||||
|
> **Проверено визуально:** обычная ходьба, прыжок, спуск и позиция «за
|
||||||
|
> решёткой шва» (straddle — там как раз работает клипающий фолбэк) —
|
||||||
|
> артефактов и следов нет.
|
||||||
|
|
||||||
|
**Ниже — исходная постановка задачи (что и почему смотрели).**
|
||||||
|
|
||||||
|
|
||||||
**Зачем сейчас.** Кадр занят на ~86 %; подготовка клипающего варианта
|
**Зачем сейчас.** Кадр занят на ~86 %; подготовка клипающего варианта
|
||||||
стоит ~5.6 К тактов на вызов, а общее ядро против линейного — 13 288 против
|
стоит ~5.6 К тактов на вызов, а общее ядро против линейного — 13 288 против
|
||||||
@@ -296,30 +333,32 @@
|
|||||||
`gfx_blit_cols_part_noclip`, иначе в клипающий вариант
|
`gfx_blit_cols_part_noclip`, иначе в клипающий вариант
|
||||||
(`pop_kid.c:86,591,676`, `pop_gdraw.c:105`).
|
(`pop_kid.c:86,591,676`, `pop_gdraw.c:105`).
|
||||||
|
|
||||||
**Что чинить:**
|
**Что чинили:**
|
||||||
|
|
||||||
- `kid_heal()` (`pop_kid.c:613,615`) и `pop_guard_heal()`
|
- ✅ `kid_heal()` и `pop_guard_heal()` звали `gfx_heal` — **всегда с
|
||||||
(`pop_gdraw.c:65,66`) зовут `gfx_heal` — **всегда с клипом**, хотя
|
клипом**, хотя `gfx_heal_noclip` существует и `heal_off` в `pop_bg.c` им
|
||||||
`gfx_heal_noclip` существует и `pop_bg.c:147` им уже пользуется по тому же
|
уже пользовался. Это heal 2–4 прямоугольников КАЖДЫЙ кадр; замер общего
|
||||||
тесту. Это heal 2–4 прямоугольников КАЖДЫЙ кадр; замер общего ядра —
|
ядра — 11 658 тактов на heal 22×22. Теперь все три идут через общий
|
||||||
11 658 тактов на heal 22×22. Тест onscreen у нас уже посчитан рядом.
|
`pop_heal_fast` (`pop_draw.c` + `_pop_draw.h`).
|
||||||
- `pop_room_clip_borders()` (`pop_bg.c:1193,1194`) — `gfx_heal(0,0,320,…)`:
|
- ⛔ `pop_room_clip_borders()` (`pop_bg.c`) — `gfx_heal(0,0,320,…)`:
|
||||||
noclip требует w,h ≤ 255, значит либо два куска по 160, либо оставить как
|
**оставлен клипающим осознанно**. Полоса шириной 320 не лезет в 8-битный
|
||||||
есть (зовётся по гейту, только в кадрах падения — проверить, что гейт
|
параметр noclip-ядра, а бить её на два куска по 160 нет смысла: гейт
|
||||||
действительно редкий, прежде чем трогать).
|
`border_dirty` пускает туда только в кадрах падения, и выигрыш подготовки
|
||||||
|
тонет в цене самих 320×28 пикселей. Причина записана прямо в коде, чтобы
|
||||||
|
не «оптимизировать» повторно.
|
||||||
|
|
||||||
**Что обязано остаться с клипом** (зафиксировать в комментарии, чтобы потом
|
**Что обязано остаться с клипом** (зафиксировано комментариями в коде):
|
||||||
не «оптимизировать» повторно):
|
- кромочные тайлы фона (`blit_b` в `pop_bg.c`) — тайл у края экрана режется
|
||||||
- кромочные тайлы фона `pop_bg.c:132` — тайл у края экрана режется по
|
по построению;
|
||||||
построению;
|
|
||||||
- спрайты при straddle (`kid_render_dx = ∓140`, комната Кида ≠ отрисованной)
|
- спрайты при straddle (`kid_render_dx = ∓140`, комната Кида ≠ отрисованной)
|
||||||
и при падении ниже поля — фолбэки `pop_kid.c:594,681`, `pop_gdraw.c:107`.
|
и при падении ниже поля — фолбэки в `kid_draw`/`pop_guard_draw`;
|
||||||
|
- борта поля (`pop_room_clip_borders`) — см. выше.
|
||||||
|
|
||||||
**Порядок работы:** (1) выписать полный список вызовов
|
**Что уже было правильно** (шаблон, который и распространили): блиты Кида,
|
||||||
`gfx_blit*`/`gfx_heal*` в roomtest с ответом «кто гарантирует on-screen»;
|
стража, клинка и брызг спрашивают `pop_onscreen_cols()` и уходят в
|
||||||
(2) перевести то, что можно, на noclip по существующему тесту; (3) замерить
|
`gfx_blit_cols_part_noclip`. Отдельный случай — `pop_kid_img_blit`: noclip
|
||||||
кадр полосами бордюра ДО/ПОСЛЕ (`PROF()` уже в `roomtest.c`) и брейкпоинтом
|
БЕЗ проверки, потому что единственный вызывающий (полоса HP) рисует по
|
||||||
на конкретной функции — числом, а не «стало плавнее»; (4) `make size-check`.
|
фиксированным координатам; это тоже помечено в коде.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -351,13 +390,17 @@ BUG-1 (провал на row 1 при переходе через открыты
|
|||||||
Список разделён на [`bug_list.md`](bug_list.md) (открытое) и
|
Список разделён на [`bug_list.md`](bug_list.md) (открытое) и
|
||||||
[`bug_closed.md`](bug_closed.md) (закрытое + разбор корней).
|
[`bug_closed.md`](bug_closed.md) (закрытое + разбор корней).
|
||||||
|
|
||||||
|
✅ **Косметика окклюзии тоже закрыта** — BUG-CEIL-1/2/3 и BUG-OCCL-1 были
|
||||||
|
починены кодом ещё в июле, а записи никто не снял: `ceil_over_kid_tile`
|
||||||
|
(`pop_bg.c:1275`), `pop_ceil_modif` + `pop_ceil_shake_draw`/`_bake_empty`
|
||||||
|
(`:547,815,827`), `bar` с `POP_YOFF+3` в `pop_room_redraw_seam_left` (`:793`),
|
||||||
|
разделение слоёв по `add_backtable` vs `ptr_add_table` в `overlay_mid_tile`
|
||||||
|
(`:1367`). Разбор — в [`bug_closed.md`](bug_closed.md).
|
||||||
|
|
||||||
⏳ **Осталось:** закрыть таблицу обхода 24 комнат
|
⏳ **Осталось:** закрыть таблицу обхода 24 комнат
|
||||||
([`bug_list.md`](bug_list.md#обход-всех-24-комнат-уровня-1)) — заполнена на
|
([`bug_list.md`](bug_list.md#обход-всех-24-комнат-уровня-1)) — заполнена на
|
||||||
5 строк из 24, инструмент (`ROOMNAV`) готов. Открытая косметика окклюзии
|
5 строк из 24, инструмент (`ROOMNAV`) готов. Делать вместе с L1-PASS: это
|
||||||
([BUG-CEIL-1](bug_list.md#bug-ceil-1),
|
единственный оставшийся источник новых багов уровня 1.
|
||||||
[BUG-CEIL-3](bug_list.md#bug-ceil-3),
|
|
||||||
[BUG-OCCL-1](bug_list.md#bug-occl-1)) остаётся Medium — трогать после
|
|
||||||
L1-PASS, обход комнат может добавить к ней новые случаи.
|
|
||||||
|
|
||||||
### L1-SPEED. Игра идёт быстрее оригинала (найдено 2026-08-01)
|
### L1-SPEED. Игра идёт быстрее оригинала (найдено 2026-08-01)
|
||||||
Сверка таймингов: оригинал — `BASE_FPS = 60` при `base_speed = 5` тиков на
|
Сверка таймингов: оригинал — `BASE_FPS = 60` при `base_speed = 5` тиков на
|
||||||
@@ -365,21 +408,19 @@ L1-PASS, обход комнат может добавить к ней новы
|
|||||||
`fight_speed = 6` = **100 мс**. У нас `roomtest.c` ждёт **три** `gfx_wait_vsync()`
|
`fight_speed = 6` = **100 мс**. У нас `roomtest.c` ждёт **три** `gfx_wait_vsync()`
|
||||||
= 60 мс, и отдельной скорости боя нет — то есть примерно **+39 % к скорости
|
= 60 мс, и отдельной скорости боя нет — то есть примерно **+39 % к скорости
|
||||||
эталона**. Соответствие: 4 ожидания (80 мс) обычно, 5 (100 мс) в бою.
|
эталона**. Соответствие: 4 ожидания (80 мс) обычно, 5 (100 мс) в бою.
|
||||||
**Делать ПОСЛЕ CLIP-1**: замедление кадра спрячет проблемы бюджета вместо
|
Условие «делать ПОСЛЕ CLIP-1» **снято** — CLIP-1 закрыт (см. P0). Проверка —
|
||||||
того, чтобы их показать. Проверка — секундомером по одинаковому отрезку
|
секундомером по одинаковому отрезку рядом с живым SDLPoP, не «на глаз».
|
||||||
рядом с живым SDLPoP, не «на глаз».
|
|
||||||
|
|
||||||
### L1-PASS. Сквозное прохождение уровня 1
|
### L1-PASS. Сквозное прохождение уровня 1
|
||||||
От старта до двери уровня одним заходом: подбор меча, страж, кнопки/ворота,
|
От старта до двери уровня одним заходом: подбор меча, страж, кнопки/ворота,
|
||||||
пики, loose-полы, зелье, падения. Это приёмка этапа 1 и одновременно
|
пики, loose-полы, зелье, падения. Это приёмка этапа 1 и одновременно
|
||||||
регресс-база для уровня 2.
|
регресс-база для уровня 2.
|
||||||
|
|
||||||
Заодно проверить на живом проходе открытую косметику окклюзии —
|
Совмещать с [таблицей обхода 24 комнат](bug_list.md#обход-всех-24-комнат-уровня-1):
|
||||||
[BUG-CEIL-1](bug_list.md#bug-ceil-1),
|
известные баги закрыты, значит новые придут только отсюда. Точки, где стоит
|
||||||
[BUG-CEIL-3](bug_list.md#bug-ceil-3),
|
смотреть внимательно, — уже закрытая косметика окклюзии (потолок при прыжке
|
||||||
[BUG-OCCL-1](bug_list.md#bug-occl-1): именно здесь станет видно, мешают ли
|
вверх, шов при анимации решётки, грани дальней колонны) и подъём на
|
||||||
они играть или это придирки на стоп-кадре. И подъём на тайл-кнопку — см.
|
тайл-кнопку: см. оговорку к BUG-3 в [`bug_closed.md`](bug_closed.md).
|
||||||
оговорку к BUG-3 в [`bug_closed.md`](bug_closed.md).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -389,9 +430,6 @@ L1-PASS, обход комнат может добавить к ней новы
|
|||||||
- **Таймер уровня / HUD времени / меню / сохранения** — Фаза 6.
|
- **Таймер уровня / HUD времени / меню / сохранения** — Фаза 6.
|
||||||
- **[T-1](bug_list.md#t-1)** (пики: перерисовка по причине) — отдаётся почти
|
- **[T-1](bug_list.md#t-1)** (пики: перерисовка по причине) — отдаётся почти
|
||||||
бесплатно после [T-2](bug_list.md#t-2), отдельно не окупается.
|
бесплатно после [T-2](bug_list.md#t-2), отдельно не окупается.
|
||||||
- **[BUG-CEIL-2](bug_list.md#bug-ceil-2)** (loose-плита в потолке из комнаты
|
|
||||||
сверху) — требует персистентного per-room modifier соседей, это Фаза P0 из
|
|
||||||
`../docs/gates_spikes_plan.md`.
|
|
||||||
- **Отключение мыши на время игры** и **замена PRNG** —
|
- **Отключение мыши на время игры** и **замена PRNG** —
|
||||||
`../docs/ideas_backlog.md` (оба дают доли процента кадра).
|
`../docs/ideas_backlog.md` (оба дают доли процента кадра).
|
||||||
- **OPT-1** (хирургический редрой шва) — решено НЕ делать, стоимость
|
- **OPT-1** (хирургический редрой шва) — решено НЕ делать, стоимость
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* _pop_draw.h — внутренний заголовок слоя отрисовки: выбор ядра libbgi
|
||||||
|
* (клипающее / линейное «noclip») по одному и тому же тесту для блита и
|
||||||
|
* для heal.
|
||||||
|
*
|
||||||
|
* ПОЧЕМУ ОТДЕЛЬНЫЙ ФАЙЛ, А НЕ pop_bg.h. Обе функции — `static inline`, а
|
||||||
|
* SDCC 4.5 оставляет тело такой функции в КАЖДОМ TU, который видит
|
||||||
|
* объявление, даже если тот её не зовёт (memory
|
||||||
|
* `sdcc_inline_codegen_findings`). pop_bg.h включают почти все модули PoP,
|
||||||
|
* то есть из общего заголовка эти ~100 Б размножились бы десятком мёртвых
|
||||||
|
* копий (замер CLIP-1, 2026-08-01: +1091 Б в _CODE и +636 Б в банке
|
||||||
|
* стража — за код, который там никто не вызывает). Здесь их видят ровно
|
||||||
|
* три файла, которые реально рисуют: pop_bg.c, pop_kid.c, pop_gdraw.c.
|
||||||
|
*/
|
||||||
|
#ifndef POP_DRAW_H
|
||||||
|
#define POP_DRAW_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <gfx.h>
|
||||||
|
|
||||||
|
/* Спрайт целиком на экране И укладывается в 8-битные параметры noclip-
|
||||||
|
* примитивов libbgi? Условие входа в gfx_blit_cols_part_noclip: клипающий
|
||||||
|
* вариант платит ~5.6 К тактов подготовки на КАЖДЫЙ вызов, независимо от
|
||||||
|
* того, вылезает край или нет. */
|
||||||
|
static inline uint8_t pop_onscreen_cols(int x, int y, uint16_t w, uint16_t h)
|
||||||
|
{
|
||||||
|
return (uint8_t)(x >= 0 && y >= 0 && w < 256 && h < 256 &&
|
||||||
|
x + (int)w <= 320 && y + (int)h <= 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Стереть прямоугольник (heal из ОЗУ-копии) тем же приёмом, что и блит:
|
||||||
|
* целиком на экране → линейное ядро без клипа. Условие входа у
|
||||||
|
* gfx_heal_noclip ровно то же, что у gfx_blit_cols_part_noclip, поэтому
|
||||||
|
* тест один — общее ядро gfx_heal платит за клип и 16-бит, а не за пиксели
|
||||||
|
* (замер: 11 658 тактов на heal 22×22).
|
||||||
|
*
|
||||||
|
* НЕ inline (тело — pop_draw.c, резидент W1): SDCC 4.5 встраивал бы его в
|
||||||
|
* каждое место вызова по 181 Б И оставлял мёртвую копию в каждом TU — см.
|
||||||
|
* шапку pop_draw.c с замером. Зовётся 5 раз за кадр, цена вызова тонет в
|
||||||
|
* стоимости самого heal.
|
||||||
|
*
|
||||||
|
* w/h тут int, а не uint16_t: вызывающие считают их вычитанием (h − skip), и
|
||||||
|
* отрицательный результат обязан быть no-op, а не превратиться в огромный
|
||||||
|
* unsigned. */
|
||||||
|
void pop_heal_fast(int x, int y, int w, int h);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -84,6 +84,72 @@ BUG-3 — дубль пункта «спуск с кнопки (room8, кром
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Косметика окклюзии — закрыта кодом, список отставал (сверено 2026-08-01)
|
||||||
|
|
||||||
|
Четыре записи от 2026-07-22 висели как открытые Medium. Каждая описывала
|
||||||
|
недостающий кусок порта; каждый из них с тех пор написан, но записи никто не
|
||||||
|
снял. Ниже — что именно закрывает каждую.
|
||||||
|
|
||||||
|
### BUG-CEIL-1. Прыжок вверх: руки Kid рисуются ПОВЕРХ потолка — **ЗАКРЫТ**
|
||||||
|
|
||||||
|
**Был симптом:** при прыжке вверх (SEQ up, кадры 67..79) руки/голова Kid
|
||||||
|
заходили в полосу кладки у потолка (row −1) и рисовались ПОВЕРХ неё.
|
||||||
|
|
||||||
|
**Чем закрыт:** `ceil_over_kid_tile()` (`pop_bg.c:1275`) — порт «нижняя грань
|
||||||
|
потолка и кадр плиты-потолка идут в FOREtable», т.е. поверх персонажа.
|
||||||
|
Зовётся из `pop_fore_over_kid` (`pop_bg.c:1575`) и из fore-прохода стража
|
||||||
|
(`:1607`). Комментарий на месте прямо называет причину: «иначе руки
|
||||||
|
прыгающего Kid лезут на кромку потолка».
|
||||||
|
|
||||||
|
### BUG-CEIL-2. Тряска/разбитие loose-плиты в потолке (row −1) — **ЗАКРЫТ**
|
||||||
|
|
||||||
|
**Был симптом:** loose-плита в ряду 2 верхнего соседа (room5 (2,5) → потолок
|
||||||
|
room6 над (0,5)) при прыжках Kid на (0,5) не тряслась и не разбивалась —
|
||||||
|
loose-состояние соседней комнаты не тянулось.
|
||||||
|
|
||||||
|
**Чем закрыт:** отдельное состояние плиты-потолка `pop_ceil_modif[10]`
|
||||||
|
(`pop_bg.c:547`, ведёт `pop_map`) + пара `pop_ceil_shake_draw()` /
|
||||||
|
`pop_ceil_bake_empty()` (`pop_bg.c:815,827`): дрожание рисуется на текущей
|
||||||
|
странице поверх фона, а провал «запекается» в ОЗУ-копию, чтобы heal его
|
||||||
|
сохранял. В полосе у потолка виден только НИЗ плиты (`draw_tile_aboveroom`),
|
||||||
|
всё выше режется клипом `POP_YOFF` — как в оригинале.
|
||||||
|
|
||||||
|
Из этого следует, что и запись «требует персистентного per-room modifier
|
||||||
|
соседей, это Фаза P0 gates_spikes_plan» больше не верна: понадобился не общий
|
||||||
|
механизм, а один массив на 10 байт под конкретный случай.
|
||||||
|
|
||||||
|
### BUG-CEIL-3. Анимация ворот стирает потолок над ними — **ЗАКРЫТ**
|
||||||
|
|
||||||
|
**Был симптом:** при анимации решётки шва полоса кладки у потолка НАД
|
||||||
|
воротами пропадала — чёрный `bar` по col0 стирал ряд −1, а redraw его не
|
||||||
|
восстанавливал.
|
||||||
|
|
||||||
|
**Чем закрыт:** `pop_room_redraw_seam_left()` (`pop_bg.c:793`) больше не
|
||||||
|
трогает полосу потолка — `bar` идёт с `POP_YOFF + 3`, а не с `POP_YOFF`:
|
||||||
|
низ полосы кладки на room-space y=2, бары ворот начинаются с y=3
|
||||||
|
(`gate_top_y = dby − 62`). Приятный побочный эффект: отпала необходимость
|
||||||
|
перерисовывать `draw_tile(-1,0)` на КАЖДОМ кадре анимации решётки — то есть
|
||||||
|
фикс не только косметический, но и вдвое дешевле прежнего.
|
||||||
|
|
||||||
|
### BUG-OCCL-1. Тень дальней колонны перекрывает Kid — **ЗАКРЫТ**
|
||||||
|
|
||||||
|
**Был симптом:** Kid у (0,4)-(0,5) частично перекрыт тёмной штриховкой —
|
||||||
|
боковой гранью ДАЛЬНЕЙ колонны, которая окклюдить персонажа не должна
|
||||||
|
(over-occlusion fore-слоя, рисовавшего fore футпринт-тайлов без учёта
|
||||||
|
глубины).
|
||||||
|
|
||||||
|
**Чем закрыт:** разделение слоёв по признаку из оригинала, а не по нашим
|
||||||
|
соображениям о глубине (`overlay_mid_tile`, `pop_bg.c:1367`). Ключ,
|
||||||
|
подтверждённый трассой оригинала: `draw_tile_right`, `draw_tile_anim_right` и
|
||||||
|
`draw_loose` кладут спрайты через `add_backtable` НАПРЯМУЮ, минуя
|
||||||
|
`ptr_add_table` — значит правая грань левого соседа («шахматка» столба 93,
|
||||||
|
blueline, грани пик/loose соседа, кадр loose) **всегда** рисуется ПОД
|
||||||
|
персонажем. Через `ptr_add_table` (→ midtable при `draw_other_overlay`) идут
|
||||||
|
только «floor B» 42 при левом соседе-поле, `draw_tile_base`,
|
||||||
|
`draw_tile_anim` (свои пики) и `draw_tile_bottom`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## BUG-SEAM-PINGPONG (#4). Пинг-понг drawn_room у шва с закрытыми воротами — **РЕШЁН 2026-07-22**
|
## BUG-SEAM-PINGPONG (#4). Пинг-понг drawn_room у шва с закрытыми воротами — **РЕШЁН 2026-07-22**
|
||||||
|
|
||||||
Настоящий корень найден потиковой трассой ЖИВОГО SDLPoP 1.23
|
Настоящий корень найден потиковой трассой ЖИВОГО SDLPoP 1.23
|
||||||
|
|||||||
@@ -8,73 +8,23 @@ odd-pixel арифметика `char_x`, подстановка тайла на
|
|||||||
Приоритеты работ — в [`TASKS.md`](TASKS.md), а не здесь. Правило проекта:
|
Приоритеты работ — в [`TASKS.md`](TASKS.md), а не здесь. Правило проекта:
|
||||||
механику сверять с `../SDLPoP/src/` ДО кодинга.
|
механику сверять с `../SDLPoP/src/` ДО кодинга.
|
||||||
|
|
||||||
Ревизия списка: **2026-08-01** (задача L1-TRIAGE). BUG-1, BUG-2 и BUG-3
|
Ревизия списка: **2026-08-01** (задача L1-TRIAGE). Закрыты и перенесены в
|
||||||
стояли как Critical с 2026-07-21 — все три прогнаны в MAME и закрыты,
|
архив семь записей: BUG-1, BUG-2, BUG-3 (стояли как Critical с 2026-07-21,
|
||||||
протокол в [`bug_closed.md`](bug_closed.md). Critical'ов сейчас нет.
|
прогнаны в MAME) и вся косметика окклюзии BUG-CEIL-1/2/3, BUG-OCCL-1 (была
|
||||||
|
починена кодом ещё в июле, список просто отстал — чем именно закрыта каждая,
|
||||||
|
расписано в [`bug_closed.md`](bug_closed.md)).
|
||||||
|
|
||||||
| ID | что | тяжесть |
|
**Открытых багов сейчас нет** — только две незакрытые оптимизации и
|
||||||
|----|-----|---------|
|
незаконченная ревизия комнат:
|
||||||
| [BUG-CEIL-1](#bug-ceil-1) | прыжок вверх: руки Kid поверх потолка | Medium |
|
|
||||||
| [BUG-CEIL-3](#bug-ceil-3) | анимация ворот стирает потолок над ними | Medium |
|
| ID | что | тип |
|
||||||
| [BUG-OCCL-1](#bug-occl-1) | тень дальней колонны перекрывает Kid | Medium |
|
|----|-----|-----|
|
||||||
| [BUG-CEIL-2](#bug-ceil-2) | loose-плита в потолке не трясётся | Medium, отложен |
|
|
||||||
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация |
|
| [T-1](#t-1) | пики перерисовываются безусловно | оптимизация |
|
||||||
| [T-2](#t-2) | Кид перерисовывается в покое | оптимизация |
|
| [T-2](#t-2) | Кид перерисовывается в покое | оптимизация |
|
||||||
| [обход 24 комнат](#обход-всех-24-комнат-уровня-1) | таблица заполнена на 5 строк из 24 | ревизия |
|
| [обход 24 комнат](#обход-всех-24-комнат-уровня-1) | таблица заполнена на 5 строк из 24 | ревизия |
|
||||||
|
|
||||||
---
|
Это НЕ значит «багов нет» — значит, что известные найдены и закрыты, а
|
||||||
|
следующая порция придёт из обхода 24 комнат и сквозного прохождения (L1-PASS).
|
||||||
<a id="bug-ceil-1"></a>
|
|
||||||
## BUG-CEIL-1. Прыжок вверх: руки Kid рисуются ПОВЕРХ потолка — **Medium**
|
|
||||||
|
|
||||||
**Симптом (2026-07-22):** при прыжке вверх (SEQ up, кадры 67..79) руки/голова
|
|
||||||
Kid заходят в полосу кладки у потолка (row -1) и рисуются ПОВЕРХ неё — потолок
|
|
||||||
должен окклюдить руки (как передняя грань).
|
|
||||||
|
|
||||||
**Где:** `pop_bg.c` — полоса потолка (`draw_tile(-1)`) сейчас только фон
|
|
||||||
(запечена в pop_room_draw), не окклюдер поверх Kid. Нужен ceiling-overlay в
|
|
||||||
`pop_fore_over_kid` (перерисовать срез полосы над Kid поверх спрайта), по
|
|
||||||
аналогии с fore-тайлами. Инфраструктура `g_clip_top`/`gfx_blit_part` уже есть.
|
|
||||||
|
|
||||||
<a id="bug-ceil-3"></a>
|
|
||||||
## BUG-CEIL-3. Анимация ворот стирает потолок над ними — **Medium**
|
|
||||||
|
|
||||||
**Симптом (2026-07-22):** при опускании/поднятии решётки шва (анимация openness)
|
|
||||||
полоса кладки у потолка НАД воротами пропадает (см. потолок над левым швом).
|
|
||||||
|
|
||||||
**Где:** `pop_bg.c` `pop_room_redraw_seam_left` (и `pop_button_redraw`/
|
|
||||||
`pop_spike_redraw` — общий класс): чёрный `bar` по col0 row0 стирает потолочную
|
|
||||||
полосу (row-1), а redraw рисует только сам гейт, не восстанавливая полосу.
|
|
||||||
Нужно: при перерисовке шва/тайла у потолка перерисовать и срез потолочной полосы
|
|
||||||
(draw_tile(-1,col) с g_clip_top) над затронутыми колонками.
|
|
||||||
|
|
||||||
<a id="bug-occl-1"></a>
|
|
||||||
## BUG-OCCL-1. Тень дальней колонны перекрывает Kid в (0,4)-(0,5) — **Medium**
|
|
||||||
|
|
||||||
**Симптом (2026-07-22):** Kid, стоя/прыгая у (0,4)-(0,5), частично перекрыт
|
|
||||||
тёмной штриховкой — это ТЕНЬ/боковая грань ДАЛЬНЕЙ колонны (сзади по глубине),
|
|
||||||
которая НЕ должна окклюдить персонажа. Over-occlusion fore-слоя.
|
|
||||||
|
|
||||||
**Где:** `pop_bg.c` `pop_fore_over_kid`/`fore_tile` — рисует fore футпринт-тайлов
|
|
||||||
без учёта глубины (какая грань РЕАЛЬНО перед Kid). Порт seg003 redraw_at_char
|
|
||||||
окклюдит только передние грани; дальняя колонна (за Kid) не должна. Сверить с
|
|
||||||
SDLPoP redraw_at_char (какие тайлы/грани идут в fore vs back по y-сортировке).
|
|
||||||
|
|
||||||
<a id="bug-ceil-2"></a>
|
|
||||||
## BUG-CEIL-2. Тряска/разбитие loose-плиты в потолке (row -1) не работает — **Medium, ОТЛОЖЕН**
|
|
||||||
|
|
||||||
**Симптом (2026-07-22):** loose-плита в ряду 2 верхнего соседа (room5 (2,5) →
|
|
||||||
потолок room6 над (0,5)) при прыжках Kid на (0,5) НЕ трясётся и не разбивается.
|
|
||||||
|
|
||||||
**Где:** верхний сосед не «живой» — `above_fg` берётся из статики уровня,
|
|
||||||
loose-состояние соседней комнаты не тянем (per-room loose/modif не персистятся).
|
|
||||||
check_press/knock работают только по текущей комнате. Нужно: (а) пробой
|
|
||||||
loose сверху через границу комнаты, (б) персистентное loose-состояние соседа +
|
|
||||||
его отрисовка в полосе. Пока полоса рисует loose статически (кадр покоя).
|
|
||||||
|
|
||||||
**Почему отложен:** требует персистентного per-room modifier соседей — это
|
|
||||||
фаза P0 из [`../docs/gates_spikes_plan.md`](../docs/gates_spikes_plan.md), а не
|
|
||||||
точечный фикс. См. «Отложено осознанно» в [`TASKS.md`](TASKS.md).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "pop_bg.h"
|
#include "pop_bg.h"
|
||||||
|
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
|
||||||
#include "pop_state.h"
|
#include "pop_state.h"
|
||||||
#include "pop_geom.h"
|
#include "pop_geom.h"
|
||||||
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
#include "pop_level.h" /* pop_doorlink2 — состояние нажатия кнопки */
|
||||||
@@ -135,18 +136,12 @@ static void blit_b(atlas_t *a, uint8_t idx, int x, int ybottom)
|
|||||||
gfx_w0_unmap();
|
gfx_w0_unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* heal в room-space (со сдвигом POP_YOFF) — все heal слоя фона/loose. */
|
/* heal в room-space (со сдвигом POP_YOFF) — все heal слоя фона/loose.
|
||||||
|
* Выбор ядра (noclip / клипающее) — общий с Кидом и стражем, pop_heal_fast
|
||||||
|
* в pop_bg.h. */
|
||||||
static void heal_off(int x, int y, int w, int h)
|
static void heal_off(int x, int y, int w, int h)
|
||||||
{
|
{
|
||||||
int sy = y + POP_YOFF;
|
pop_heal_fast(x, y + POP_YOFF, w, h);
|
||||||
/* Без клипа — линейным ядром (~2.9×, как gfx_blit_noclip): общий
|
|
||||||
* gfx_heal платит за клип/16-бит/split, а не за пиксели (замер:
|
|
||||||
* 11 658 тактов на heal 22×22). */
|
|
||||||
if (x >= 0 && sy >= 0 && w > 0 && h > 0 && w < 256 && h < 256 &&
|
|
||||||
x + w <= 320 && sy + h <= 256)
|
|
||||||
gfx_heal_noclip(x, sy, (uint8_t)w, (uint8_t)h);
|
|
||||||
else
|
|
||||||
gfx_heal(x, sy, w, h);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Область, куда в этом кадре рисовался ОВЕРЛЕЙ (не футпринт fore, а
|
/* Область, куда в этом кадре рисовался ОВЕРЛЕЙ (не футпринт fore, а
|
||||||
@@ -1190,6 +1185,11 @@ void pop_room_clip_borders(void) __banked
|
|||||||
{
|
{
|
||||||
if (!border_dirty) return;
|
if (!border_dirty) return;
|
||||||
border_dirty--;
|
border_dirty--;
|
||||||
|
/* ОСТАЁТСЯ клипающим осознанно (CLIP-1, 2026-08-01): полоса шириной 320
|
||||||
|
* не лезет в 8-битный параметр noclip-ядра, а разбивать её на два куска
|
||||||
|
* по 160 нет смысла — гейт border_dirty пускает сюда только в кадрах
|
||||||
|
* падения/выхода за поле, и выигрыш (~2×5.6 К тактов подготовки) там
|
||||||
|
* тонет в цене самих 320×28 пикселей. Не «оптимизировать» повторно. */
|
||||||
gfx_heal(0, 0, 320, POP_YOFF); /* верхний борт */
|
gfx_heal(0, 0, 320, POP_YOFF); /* верхний борт */
|
||||||
gfx_heal(0, POP_CLIP_BOTTOM, 320, 256 - POP_CLIP_BOTTOM);/* статус-полоса + нижний борт */
|
gfx_heal(0, POP_CLIP_BOTTOM, 320, 256 - POP_CLIP_BOTTOM);/* статус-полоса + нижний борт */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,18 +25,10 @@
|
|||||||
/* Экранный y нижней границы поля (ниже — статус-полоса + борт → клип). */
|
/* Экранный y нижней границы поля (ниже — статус-полоса + борт → клип). */
|
||||||
#define POP_CLIP_BOTTOM (POP_YOFF + POP_PLAYFIELD_H)
|
#define POP_CLIP_BOTTOM (POP_YOFF + POP_PLAYFIELD_H)
|
||||||
|
|
||||||
/* Спрайт целиком на экране И укладывается в 8-битные параметры noclip-
|
/* Выбор ядра libbgi (pop_onscreen_cols / pop_heal_fast) переехал в
|
||||||
* примитивов libbgi? Условие входа в gfx_blit_cols_part_noclip: клипающий
|
* `_pop_draw.h` — его включают только три рисующих модуля. Из общего
|
||||||
* вариант платит ~5.6 К тактов подготовки на КАЖДЫЙ вызов, независимо от
|
* заголовка SDCC размножал мёртвые копии этих inline'ов по всем TU: см.
|
||||||
* того, вылезает край или нет.
|
* шапку `_pop_draw.h`. */
|
||||||
* static inline, а не чистый inline: SDCC оставляет мёртвое тело в каждом TU
|
|
||||||
* (memory sdcc_inline_codegen_findings), но здесь это ~30 байт на два TU —
|
|
||||||
* дешевле риска неразрешённой ссылки. */
|
|
||||||
static inline uint8_t pop_onscreen_cols(int x, int y, uint16_t w, uint16_t h)
|
|
||||||
{
|
|
||||||
return (uint8_t)(x >= 0 && y >= 0 && w < 256 && h < 256 &&
|
|
||||||
x + (int)w <= 320 && y + (int)h <= 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Загрузить 7 атласов фона. Звать ДО initgraph (как poc.c — atlas_load
|
/* Загрузить 7 атласов фона. Звать ДО initgraph (как poc.c — atlas_load
|
||||||
* трогает W3; проверенный порядок). Палитру pop_bg.pal грузит ПРИЛОЖЕНИЕ
|
* трогает W3; проверенный порядок). Палитру pop_bg.pal грузит ПРИЛОЖЕНИЕ
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* pop_draw.c — выбор ядра libbgi для heal: линейное «noclip», если
|
||||||
|
* прямоугольник целиком на экране, иначе общее клипающее. Объявление и
|
||||||
|
* мотивация — `_pop_draw.h`.
|
||||||
|
*
|
||||||
|
* ПОЧЕМУ ОТДЕЛЬНЫЙ РЕЗИДЕНТНЫЙ МОДУЛЬ, а не inline в заголовке. Замер
|
||||||
|
* CLIP-1 (2026-08-01), SDCC 4.5: `static inline` тут обходится втридорога —
|
||||||
|
* компилятор И встраивает тело в каждый вызов (181 Б на место), И оставляет
|
||||||
|
* отдельную мёртвую копию в каждом TU. У стража это раздуло
|
||||||
|
* `pop_guard_heal` с ~60 до 663 Б. Пяти местам вызова это стоило бы ~1.4 КБ
|
||||||
|
* ради экономии ~50 тактов на вызов — при том что BANK2 занят на 86 %.
|
||||||
|
*
|
||||||
|
* Резидент W1 (_CODE), а не банк: сюда зовут из ДВУХ разных банков
|
||||||
|
* (pop_bg.c → BANK2, pop_gdraw.c → BANK4) и из резидента (pop_kid.c). W1
|
||||||
|
* замаплено всегда, поэтому из банка это обычный `call` без трамплина —
|
||||||
|
* тот же приём, что у pop_sword_draw.
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <gfx.h>
|
||||||
|
#include "_pop_draw.h"
|
||||||
|
|
||||||
|
void pop_heal_fast(int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
if (w <= 0 || h <= 0) return;
|
||||||
|
if (pop_onscreen_cols(x, y, (uint16_t)w, (uint16_t)h))
|
||||||
|
gfx_heal_noclip(x, y, (uint8_t)w, (uint8_t)h);
|
||||||
|
else
|
||||||
|
gfx_heal(x, y, w, h);
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "pop_guard.h"
|
#include "pop_guard.h"
|
||||||
#include "pop_kid.h" /* pop_sword_draw — клинок общий с Кидом */
|
#include "pop_kid.h" /* pop_sword_draw — клинок общий с Кидом */
|
||||||
#include "pop_bg.h" /* POP_YOFF, pop_fore_over_char */
|
#include "pop_bg.h" /* POP_YOFF, pop_fore_over_char */
|
||||||
|
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
|
||||||
#include "pop_map.h" /* hitp_curr/hitp_max — HP Кида */
|
#include "pop_map.h" /* hitp_curr/hitp_max — HP Кида */
|
||||||
#include "kid_data.h"
|
#include "kid_data.h"
|
||||||
|
|
||||||
@@ -59,11 +60,15 @@ void pop_guard_free(void) __banked
|
|||||||
g_ok = 0;
|
g_ok = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Стирание прошлого кадра стража и его клинка. pop_heal_fast — по той же
|
||||||
|
* причине, что в kid_heal: стираем ровно то, что рисовали, а рисовали в
|
||||||
|
* большинстве кадров noclip-ядром. Два прямоугольника, а не объединение
|
||||||
|
* (см. комментарий к sx_l выше). */
|
||||||
void pop_guard_heal(void) __banked
|
void pop_guard_heal(void) __banked
|
||||||
{
|
{
|
||||||
uint8_t p = gfx_get_draw_page() & 1;
|
uint8_t p = gfx_get_draw_page() & 1;
|
||||||
if (gvalid[p]) gfx_heal(gx_l[p], gy_l[p] + POP_YOFF, gw_l[p], gh_l[p]);
|
if (gvalid[p]) pop_heal_fast(gx_l[p], gy_l[p] + POP_YOFF, gw_l[p], gh_l[p]);
|
||||||
if (svalid[p]) gfx_heal(sx_l[p], sy_l[p] + POP_YOFF, sw_l[p], sh_l[p]);
|
if (svalid[p]) pop_heal_fast(sx_l[p], sy_l[p] + POP_YOFF, sw_l[p], sh_l[p]);
|
||||||
gvalid[p] = svalid[p] = 0;
|
gvalid[p] = svalid[p] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "pop_kid.h"
|
#include "pop_kid.h"
|
||||||
#include "pop_guard.h" /* Guard/pop_gframe/CHARID_* — интерпретатор общий */
|
#include "pop_guard.h" /* Guard/pop_gframe/CHARID_* — интерпретатор общий */
|
||||||
#include "pop_bg.h" /* POP_YOFF — вертикальное центрирование */
|
#include "pop_bg.h" /* POP_YOFF — вертикальное центрирование */
|
||||||
|
#include "_pop_draw.h" /* pop_onscreen_cols / pop_heal_fast */
|
||||||
#include "pop_map.h" /* pop_clip_char_top (clip_char) */
|
#include "pop_map.h" /* pop_clip_char_top (clip_char) */
|
||||||
#include "pop_geom.h"
|
#include "pop_geom.h"
|
||||||
#include "kid_data.h"
|
#include "kid_data.h"
|
||||||
@@ -108,7 +109,9 @@ void pop_kid_img_blit(uint8_t image, int x, int y)
|
|||||||
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
|
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
|
||||||
/* Атласы Кида хранятся COLUMN-MAJOR (transpose_cols в pop_pack_kid —
|
/* Атласы Кида хранятся COLUMN-MAJOR (transpose_cols в pop_pack_kid —
|
||||||
* ради бесплатного горизонтального флипа), поэтому блит обязан быть
|
* ради бесплатного горизонтального флипа), поэтому блит обязан быть
|
||||||
* колоночным. Row-major gfx_blit_noclip выдал бы марку транспонированной. */
|
* колоночным. Row-major gfx_blit_noclip выдал бы марку транспонированной.
|
||||||
|
* noclip БЕЗ проверки (CLIP-1): единственный вызывающий — полоса HP
|
||||||
|
* (pop_gdraw.c), у неё координаты фиксированные и заведомо на экране. */
|
||||||
if (w && h) gfx_blit_cols_part_noclip(x, y, img, 0, 0, 0);
|
if (w && h) gfx_blit_cols_part_noclip(x, y, img, 0, 0, 0);
|
||||||
gfx_w0_unmap();
|
gfx_w0_unmap();
|
||||||
}
|
}
|
||||||
@@ -605,14 +608,20 @@ void kid_draw_splash(void)
|
|||||||
gfx_w0_unmap();
|
gfx_w0_unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Восстановить фон из теневой копии на месте ПРЕДЫДУЩЕГО кадра Kid. */
|
/* Восстановить фон из теневой копии на месте ПРЕДЫДУЩЕГО кадра Kid.
|
||||||
|
*
|
||||||
|
* pop_heal_fast, а не голый gfx_heal: прямоугольник тут — это ровно тот
|
||||||
|
* прямоугольник, который kid_draw нарисовал noclip-ядром, то есть в
|
||||||
|
* подавляющем большинстве кадров он заведомо на экране. Клипающий путь
|
||||||
|
* остаётся для straddle (kid_render_dx = ∓140) и падения ниже поля —
|
||||||
|
* там координата реально уходит за экран. */
|
||||||
void kid_heal(void)
|
void kid_heal(void)
|
||||||
{
|
{
|
||||||
uint8_t p = gfx_get_draw_page();
|
uint8_t p = gfx_get_draw_page();
|
||||||
if (kid_lvalid[p])
|
if (kid_lvalid[p]) /* +YOFF: центрирование */
|
||||||
gfx_heal(kid_lx[p], kid_ly[p] + POP_YOFF, kid_lw[p], kid_lh[p]); /* +YOFF: центрирование */
|
pop_heal_fast(kid_lx[p], kid_ly[p] + POP_YOFF, kid_lw[p], kid_lh[p]);
|
||||||
if (kid_ovalid[p])
|
if (kid_ovalid[p])
|
||||||
gfx_heal(kid_ox[p], kid_oy[p] + POP_YOFF, kid_ow[p], kid_oh[p]);
|
pop_heal_fast(kid_ox[p], kid_oy[p] + POP_YOFF, kid_ow[p], kid_oh[p]);
|
||||||
kid_lvalid[p] = kid_ovalid[p] = 0;
|
kid_lvalid[p] = kid_ovalid[p] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user