Ресурсы — в архивы PBA1; тайминги сцены PV — по часам насоса CBL
ТАЙМИНГИ. Пользователь заметил, что заклинание Джафара не совпадает с музыкой. Замер в MAME (breakpoint на вспышке + курсор трека): реплика m53 успевала ДОИГРАТЬ до молнии, хотя по шкале оригинала между входом Джафара и заклинанием ровно 822 тика = 13,7 с. Причина: пейсинг считал НАШИ ожидания vsync, а не прошедшее время. Полноэкранная копия страницы стоит больше кадра луча, и разница копилась. Кадровые прерывания для счёта не годятся (теряются в di-окнах акселератора), поэтому часами стал насос CBL: он идёт от расхода буфера железом, 85,4 Гц, и ему безразлично, чем занят главный цикл. Один тик оригинала = 57/40 тика насоса (0,07 % ошибки, без деления в кадре). Когда звук выключен, работает прежний путь по кадрам луча. После фикса замер даёт 229 блоков остатка m53 против расчётных 233 — расхождение 47 мс. АРХИВЫ. Группы ресурсов сложены в PBA1: kid (58 атласов), pv (78), shadow (32), bg (25), title (20), guard (10), vizier (5), skel (4). Было 232 файла на образе, стало 8 архивов плюс шесть палитр и таблицы уровней. При цене `open` 51,4 мс против 32,6 мс за чтение 16 КБ это возвращает секунды на каждой загрузке. - pop_pack_arc.py печатает индексы элементов константами (ARC_<GRP>_<FILE>), порядок задаёт Makefile, а серии код проверяет статически; - atlas_load разделён: atlas_attach принимает уже прочитанную страницу, поэтому чтение из архива не дублирует проверку магии и подготовку W0; - имена архивов живут в pop_arc.c и адресуются номером. Строковый литерал лежит в rodata своего банка, и указатель на него из другого банка после переключения W3 показывает на чужие данные — ровно так падала загрузка фона (поймано брейкпоинтом на puts). Проверено в MAME: заставка, интро и уровень 1 собираются из архивов, Тень грузит все 32 страницы. Host-тесты: 15 наборов. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,10 @@
|
||||
#include <graphics.h>
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
#include "pop_arc.h"
|
||||
#include "guard_arc.h"
|
||||
#include "skel_arc.h"
|
||||
#include "vizier_arc.h"
|
||||
#include "pop_guard.h"
|
||||
#include "pop_kid.h"
|
||||
#include "_pop_kdraw.h"
|
||||
@@ -107,31 +111,30 @@ pop_cdraw_t pop_cd[POP_CH_N];
|
||||
* грузит. Уровень БЕЗ соперников (type < 0) не грузит ничего. */
|
||||
int pop_guard_load(void) __banked
|
||||
{
|
||||
static const char *const guard_names[GUARD_PAGES] = {
|
||||
"GUARD\\g0.atl", "GUARD\\g1.atl", "GUARD\\g2.atl",
|
||||
"GUARD\\g3.atl", "GUARD\\g4.atl"
|
||||
};
|
||||
static const char *const skel_names[GUARD_PAGES] = {
|
||||
"SKEL\\g0.atl", "SKEL\\g1.atl", "SKEL\\g2.atl",
|
||||
"SKEL\\g3.atl", 0
|
||||
};
|
||||
/* Джафар (уровень 13, tbl_guard_type == 3) — VIZIER.DAT: кадров столько
|
||||
* же, сколько у стража, страниц пять. */
|
||||
static const char *const vizier_names[GUARD_PAGES] = {
|
||||
"VIZIER\\g0.atl", "VIZIER\\g1.atl", "VIZIER\\g2.atl",
|
||||
"VIZIER\\g3.atl", "VIZIER\\g4.atl"
|
||||
};
|
||||
const char *const *names;
|
||||
uint8_t tbl[ARC_GUARD_COUNT * POP_ARC_REC]; /* самый крупный из трёх */
|
||||
pop_arc_t arc;
|
||||
int8_t type = pop_level_guard_type(pop_current_level);
|
||||
uint8_t i;
|
||||
uint8_t i, pages, count, id;
|
||||
|
||||
if (type < 0) return 0; /* соперников на уровне нет */
|
||||
names = (type == 2) ? skel_names : (type == 3) ? vizier_names : guard_names;
|
||||
for (i = 0; i < GUARD_PAGES; i++) {
|
||||
if (names[i] == 0) break;
|
||||
if (atlas_load(&gp[i], names[i]) != 0) return -1;
|
||||
}
|
||||
/* Наборы разложены по своим архивам, а не в один: имена внутри у них
|
||||
* совпадают (g0.atl у всех троих), да и грузится всегда ровно один. */
|
||||
if (type == 2) { id = POP_ARC_SKEL; count = ARC_SKEL_COUNT;
|
||||
pages = ARC_SKEL_COUNT; }
|
||||
else if (type == 3) { id = POP_ARC_VIZIER; count = ARC_VIZIER_COUNT;
|
||||
pages = ARC_VIZIER_COUNT; }
|
||||
else { id = POP_ARC_GUARD; count = ARC_GUARD_COUNT;
|
||||
pages = GUARD_PAGES; }
|
||||
if (pages > GUARD_PAGES) pages = GUARD_PAGES;
|
||||
if (pop_arc_open_id(&arc, id, tbl, count) < 0) return -1;
|
||||
for (i = 0; i < pages; i++)
|
||||
if (pop_arc_atlas(&arc, tbl, i, &gp[i]) != 0) {
|
||||
pop_arc_close(&arc);
|
||||
return -1;
|
||||
}
|
||||
pop_arc_close(&arc);
|
||||
g_ok = 1;
|
||||
/* Цвет: у скелета он СВОЙ (палитра из его набора), у стража подменяется
|
||||
/* Цвет: у скелета он СВОЙ (палитра из его набора), у стража подменяется
|
||||
* из res10.bin по guards_color — это делает pop_guard_set_palette при
|
||||
* входе в комнату (seg002:186: у не-guard curr_guard_color = 0). */
|
||||
pop_guard_pal_apply();
|
||||
@@ -143,24 +146,29 @@ int pop_guard_load(void) __banked
|
||||
* потому что gp[] и выбор GUARD/SKEL живут именно тут. */
|
||||
int pop_guard_vflip_load(void) __banked
|
||||
{
|
||||
static const char *const guard_v[GUARD_PAGES] = {
|
||||
"GUARD\\g0_v.atl", "GUARD\\g1_v.atl", "GUARD\\g2_v.atl",
|
||||
"GUARD\\g3_v.atl", "GUARD\\g4_v.atl"
|
||||
};
|
||||
static const char *const skel_v[GUARD_PAGES] = {
|
||||
"SKEL\\g0_v.atl", "SKEL\\g1_v.atl", "SKEL\\g2_v.atl",
|
||||
"SKEL\\g3_v.atl", 0
|
||||
};
|
||||
const char *const *names;
|
||||
uint8_t tbl[ARC_GUARD_COUNT * POP_ARC_REC];
|
||||
pop_arc_t arc;
|
||||
int8_t type = pop_level_guard_type(pop_current_level);
|
||||
uint8_t i;
|
||||
int res = 0;
|
||||
|
||||
if (type < 0 || !g_ok) return 0; /* соперников на уровне нет */
|
||||
names = (type == 2) ? skel_v : guard_v;
|
||||
/* Зеркала есть ТОЛЬКО у обычного стража: зелье инверсии — уровень 9, а
|
||||
* там tbl_guard_type = 0 (у скелета и Джафара своих *_v нет вовсе). */
|
||||
if (type != 0 && type != 1) return 0;
|
||||
if (pop_arc_open_id(&arc, POP_ARC_GUARD, tbl, ARC_GUARD_COUNT) < 0)
|
||||
return -1;
|
||||
for (i = 0; i < GUARD_PAGES; i++) {
|
||||
if (names[i] == 0) break;
|
||||
if (pop_vflip_add(&gp[i], names[i]) != 0) return -1;
|
||||
atlas_t m;
|
||||
|
||||
if (pop_arc_atlas(&arc, tbl, (uint8_t)(ARC_GUARD_G0_V + i), &m) != 0 ||
|
||||
pop_vflip_take(&gp[i], &m) != 0) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
pop_arc_close(&arc);
|
||||
return res;
|
||||
}
|
||||
|
||||
void pop_guard_free(void) __banked
|
||||
|
||||
Reference in New Issue
Block a user