Фиксированный логический кадр по лучу + режимы FASTEST/FAST/NORMAL
Период стал max(n, ceil(W)) вместо ceil(W)+2: три gfx_wait_vsync после работы отсчитывались от её КОНЦА, поэтому бюджет кадра был один растр. Теперь ждём от якоря начала кадра, и при n=3 бюджет 1 290 240 тактов. Счёт кадров — программный, по биту 5 порта 0xFE (положение луча), а не по кадровым прерываниям: те теряются в DI-окнах акселератора фазозависимо (замер: 0..2,8 %, на полной перерисовке три подряд). Условие точности одно — зазор между выборками меньше 64 512 тактов; точки выборки расставлены по замеру, а не на глаз. Режимы (pop_pace.h), клавиша P по кругу, дефолт FASTEST. Условие боя взято у оригинала буквально (SDLPoP seg003.c:363): Kid.sword == SWORD_2_DRAWN, а не «идёт бой». Проверено в MAME на 11/15: счётчик без недосчёта на 270 кадров, период ровно 3 растра на 302 логических кадрах (ни длиннее 3,1, ни короче 2,9), NORMAL даёт ровно 4, с вынутым мечом — ровно 5.
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include "pop_cheat.h"
|
||||
#include "pop_tune.h"
|
||||
#include "pop_vflip.h" /* зеркальный набор персонажей (зелье инверсии) */
|
||||
#include "pop_pace.h" /* фиксированный логический кадр по лучу */
|
||||
#include "roomtest_cold.h" /* холодная половина цикла — в банке */
|
||||
|
||||
__sfr __at (0xFE) io_border;
|
||||
@@ -225,6 +226,7 @@ int main(void)
|
||||
* по умолчанию (без мерцания); SPACE переключает в однобуфер для
|
||||
* отладки багов рисования (edge по sp_prev, чтоб не дёргать). */
|
||||
uint8_t front = 0, back, dbuf = 1, sp_prev = 0, frozen = 0;
|
||||
uint8_t pace_prev = 0; /* edge клавиши смены режима скорости */
|
||||
uint8_t skip = 0; /* маска «слот перерисовывать не надо» */
|
||||
uint16_t dead_frames = 0;
|
||||
#ifdef ROOMNAV
|
||||
@@ -243,6 +245,9 @@ int main(void)
|
||||
return 1;
|
||||
}
|
||||
gfx_set_idle_hook(kbd_idle); /* вычерпывать FIFO, пока ждём кадр */
|
||||
/* Темп кадра по лучу. Если бит 5 порта 0xFE не шевелится (иное
|
||||
* железо), pop_pace_* молча откатываются на прежние gfx_wait_vsync. */
|
||||
pop_pace_arm();
|
||||
|
||||
while (!kbd_raw_down(KBD_ESC)) {
|
||||
/* SPACE — тумблер дабл-буфера (edge, чтоб одно нажатие = один
|
||||
@@ -260,6 +265,18 @@ int main(void)
|
||||
}
|
||||
sp_prev = sp;
|
||||
|
||||
/* P — переключить режим скорости по кругу (FASTEST -> FAST ->
|
||||
* NORMAL). Edge, чтоб одно нажатие = один шаг. Дефолт FASTEST
|
||||
* (crt0 зануляет _DATA). Что означают режимы — pop_pace.h. */
|
||||
{
|
||||
uint8_t pk = kbd_raw_down(KBD_SPEED_MODE);
|
||||
if (pk && !pace_prev) {
|
||||
uint8_t m = (uint8_t)(pop_speed_mode + 1);
|
||||
pop_speed_mode = (uint8_t)(m >= POP_SPEED_MODES ? 0 : m);
|
||||
}
|
||||
pace_prev = pk;
|
||||
}
|
||||
|
||||
/* Отладочный стоп-кадр: '1' (PS/2 0x16) — заморозить, '2' (0x1E) —
|
||||
* продолжить. В заморозке пропускаем весь tick/draw/flip: картинка
|
||||
* стоит, можно спокойно разбирать позу Kid и окклюзию. */
|
||||
@@ -317,7 +334,10 @@ int main(void)
|
||||
}
|
||||
if (frozen) {
|
||||
PROF(0); /* чёрный: ждём vsync */
|
||||
gfx_wait_vsync();
|
||||
/* Заморозка — тоже полноценный логический кадр: иначе якорь
|
||||
* пейсинга уедет и первый кадр после разморозки будет рваным. */
|
||||
pop_wait_edge();
|
||||
pop_pace_end(pop_pace_n((uint8_t)(Kid.sword == SWORD_2_DRAWN)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -362,14 +382,18 @@ int main(void)
|
||||
gfx_set_draw_page(back);
|
||||
}
|
||||
pop_dbg_m13(); /* ЗАМЕР: ввод и читы разобраны */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_check_skel(); /* спецсобытие ур.3: скелет встаёт */
|
||||
pop_check_mouse(); /* спецсобытие ур.8: мышь жмёт кнопку */
|
||||
pop_check_killed_shadow(); /* спецсобытие ур.12: смерть тени = смерть Кида */
|
||||
pop_frame_timers(); /* timers (seg003:0735): вспышка слияния */
|
||||
pop_dbg_m9(); /* ЗАМЕР: pop_frame_timers сделан */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_check_can_guard_see_kid(); /* луч видимости — ДО логики персонажей */
|
||||
pop_dbg_m14(); /* ЗАМЕР: спецсобытия + луч видимости */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_ctrl_tick(); /* ввод -> control(): смена seq */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
/* Кто в этом кадре не изменился с прошлой отрисовки ЭТОЙ страницы —
|
||||
* тот на ней уже нарисован правильно: ни стирать, ни рисовать заново
|
||||
* не надо (DRAW-COST, контракт в pop_cdraw.h). Решение
|
||||
@@ -381,18 +405,25 @@ int main(void)
|
||||
* skip-маске он не участвует (рисуется/стирается безусловно, живёт
|
||||
* только пока Кид стоит на тайле зеркала). */
|
||||
pop_mirror_heal();
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_fore_heal(); /* + следы оверлея (шире прямоугольника Kid) */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
PROF(2); /* логика (тот же синий) */
|
||||
pop_dbg_m1(); /* ЗАМЕР: начало логики */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
kid_tick(); /* play_seq: следующий кадр */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_phys_tick(); /* K3: падение/приземление/стена */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_guard_tick(); /* логика стража — В БАНКЕ (guards.c) */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_guard_phys_tick(); /* и его физика — та же, что у Кида (play_guard_frame) */
|
||||
/* Боёвка, порядок как в play_frame (seg000:872): сначала пометить
|
||||
* попадания с обеих сторон, потом применить, потом свести HP. */
|
||||
pop_check_sword_hurting();
|
||||
pop_check_sword_hurt();
|
||||
pop_do_delta_hp();
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_guard_fallout(); /* страж провалился ниже комнаты — убрать (seg002:241) */
|
||||
if (pop_fell_out) { /* Kid пересёк нижнюю границу комнаты */
|
||||
uint8_t down = pop_room_link(cur_room, LINK_DOWN);
|
||||
@@ -460,10 +491,12 @@ int main(void)
|
||||
|
||||
PROF(4); /* слой фона */
|
||||
pop_dbg_m2(); /* ЗАМЕР: конец логики / начало фона */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
|
||||
pop_loose_tick(); /* loose-полы: анимация + перерисовка (СЛОЙ ФОНА */
|
||||
/* — ДО Kid, чтобы Kid всегда был поверх плиты) */
|
||||
pop_dbg_m5(); /* ЗАМЕР: pop_loose_tick сделан */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_process_trobs(cur_room); /* пики/ворота/дверь: продвинуть СОСТОЯНИЕ (порт */
|
||||
/* process_trobs — рисования внутри нет) */
|
||||
if (pop_neigh_dirty) {
|
||||
@@ -491,8 +524,10 @@ int main(void)
|
||||
}
|
||||
}
|
||||
pop_dbg_m6(); /* ЗАМЕР: pop_process_trobs сделан */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_redraw_needed();
|
||||
pop_dbg_m7(); /* ЗАМЕР: pop_redraw_needed сделан */ /* и разобрать пометки перерисовки тайлов (порт */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
/* redraw_needed, seg008:0178) — СЛОЙ ФОНА, до Kid */
|
||||
{ /* ворота соседа слева (room8) видны в col0 — */
|
||||
uint8_t lft = pop_room_link(cur_room, 0); /* редрой шва ТОЛЬКО при изменении openness */
|
||||
@@ -630,6 +665,7 @@ int main(void)
|
||||
update_kid_render_dx(); /* straddle: смещение спрайта, если kid_room≠cur_room */
|
||||
PROF(6); /* спрайты: страж, Kid, fore поверх */
|
||||
pop_dbg_m3(); /* ЗАМЕР: конец фона / начало спрайтов */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
/* check_mirror (seg003:0798) — ПЕРВАЯ строка draw_people
|
||||
* (seg008:228A), до отрисовки кого бы то ни было: если Кид только что
|
||||
* пролетел сквозь зеркало, тень должна родиться ДО того, как слот
|
||||
@@ -640,8 +676,10 @@ int main(void)
|
||||
* спрайта, иначе перепечатка ложится поверх уже нарисованного куска —
|
||||
* так окно задней стены и передняя грань пола оказывались на плите. */
|
||||
pop_dbg_m10(); /* ЗАМЕР: check_mirror сделан */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_loose_mob_draw();
|
||||
pop_dbg_m11(); /* ЗАМЕР: pop_loose_mob_draw сделан */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
{ /* Кто позже — тот поверх; порядок задаёт обход тайлов, а не роль
|
||||
* персонажа (см. guard_over_kid). Отрисовка одна на всех Char
|
||||
* (pop_cdraw.c), различает их только слот. */
|
||||
@@ -651,6 +689,7 @@ int main(void)
|
||||
uint8_t g_after;
|
||||
skip = pop_char_skip_mask();
|
||||
pop_dbg_m12(); /* ЗАМЕР: skip_mask сделан */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
/* Порядок «кто поверх кого» нужен, только если кого-то РИСУЕМ.
|
||||
* При skip == 3 оба слота тихие, рисовать некого — а вызов стоит
|
||||
* трамплина в банк 8 и двух objtile_at_char, 14 424 такта
|
||||
@@ -682,7 +721,9 @@ int main(void)
|
||||
* оригинала (draw_tables, seg008:1373). Пометки ставят сами
|
||||
* объекты вокруг себя (pop_redraw.h). */
|
||||
pop_fore_needed();
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_hp_draw(); /* полоса HP — только при изменении */
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
PROF(6); /* fore поверх Kid + борта */
|
||||
/* Fore-слой Кида — В КОНЦЕ, после плиты и полосы HP: окно fore-клипа
|
||||
* одно на всех, и его ставит каждый, кто рисовал персонажа, поэтому
|
||||
@@ -695,11 +736,18 @@ int main(void)
|
||||
* взводит бит и обязан быть учтён. Всё, что рисуется ниже
|
||||
* (mob поверх Кида, борта), взводит его заново само. */
|
||||
pop_cd_clear(back);
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_room_clip_borders(); /* почистить борта — только в кадрах падения (гейт) */
|
||||
|
||||
/* Пейсинг 3 кадра, затем tear-free флип на vblank: draw уже
|
||||
* сделан (скрытая страница), wait_vsync ловит начало кадра,
|
||||
* set_visible_page переключает во время бланка (gfx.h паттерн). */
|
||||
/* ФИКСИРОВАННЫЙ ЛОГИЧЕСКИЙ КАДР (pop_pace.h): период = max(n,
|
||||
* ceil(W)) вместо прежнего ceil(W) + 2. Раньше здесь стояли три
|
||||
* gfx_wait_vsync ПОДРЯД — они отсчитывались от КОНЦА работы, из-за
|
||||
* чего бюджет кадра был один растр, а превышение его на такт стоило
|
||||
* целого лишнего. Теперь ждём от ЯКОРЯ начала кадра.
|
||||
*
|
||||
* Первый фронт — всегда: на нём и происходит tear-free своп (до
|
||||
* начала картинки остаётся верхний бордер, 16 строк). Строб вспышки
|
||||
* снимается ровно между первым фронтом и остальными, как и было. */
|
||||
|
||||
PROF(0); /* чёрный: ждём vsync */
|
||||
|
||||
@@ -711,13 +759,15 @@ int main(void)
|
||||
#endif
|
||||
|
||||
pop_dbg_m4(); /* ЗАМЕР: конец спрайтов */
|
||||
gfx_wait_vsync();
|
||||
pop_beam_sample(); /* ТЕМП КАДРА: выборка луча (pop_pace.h) */
|
||||
pop_wait_edge();
|
||||
if (flash_on) { /* строб: цвет держался один кадр растра */
|
||||
flash_bg(0, 0, 0);
|
||||
flash_on = 0;
|
||||
}
|
||||
gfx_wait_vsync();
|
||||
gfx_wait_vsync();
|
||||
/* Условие боя — буквально как у оригинала (SDLPoP seg003.c:363):
|
||||
* не «идёт бой» и не «рядом страж», а «у Кида ВЫНУТ МЕЧ». */
|
||||
pop_pace_end(pop_pace_n((uint8_t)(Kid.sword == SWORD_2_DRAWN)));
|
||||
if (dbuf) {
|
||||
gfx_set_visible_page(back);
|
||||
front = back;
|
||||
|
||||
Reference in New Issue
Block a user