Проверка «задет ли слот» без пяти аргументов: минус 3 684
pop_cd_hit принимает (p, x0, y0, x1, y1) — три последних идут стеком, и функция целиком уезжает в IX-фрейм: 45 % её тактов на `-n(ix)` (asm). А зовут её из cd_quiet до восьми раз за кадр. Новый pop_cd_hit_slot(who, p) берёт координаты прямо из pop_cd, а само сравнение вынесено в hit_rect с file-scope аргументами. Первая попытка — обёртка, которая внутри всё равно звала pop_cd_hit — не дала ничего (1799 Z80 вместо 1318, то есть стало хуже), и это записано здесь, чтобы не повторять: снимать аргументы со стека нужно у ТОГО, кто их читает. asm на путь «спрайт + накладной»: было 1799 + 2x1318 = 4435 тактов Z80, стало 1221 + 2x1009 = 3239 (-27 %). Замер 11/15, лёгкая позиция: синяя 219 894 -> 218 052, циан 41 280 -> 39 438, работа кадра 442 662 -> 438 978. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -414,17 +414,7 @@ static uint8_t cd_quiet(uint8_t who, uint8_t p)
|
||||
*
|
||||
* Для skip_mask объединение по-прежнему годится: там вопрос «рядом ли
|
||||
* два слота», и загрубление в бОльшую сторону безопасно. */
|
||||
const pop_cdraw_t *q = &pop_cd[who];
|
||||
int y0 = q->y[p] + POP_YOFF;
|
||||
if (pop_cd_hit(p, q->x[p], y0,
|
||||
q->x[p] + (int)q->w[p] - 1, y0 + (int)q->h[p] - 1))
|
||||
return 0;
|
||||
if (q->ovalid[p]) {
|
||||
int oy = q->oy[p] + POP_YOFF;
|
||||
if (pop_cd_hit(p, q->ox[p], oy,
|
||||
q->ox[p] + (int)q->ow[p] - 1, oy + (int)q->oh[p] - 1))
|
||||
return 0;
|
||||
}
|
||||
if (pop_cd_hit_slot(who, p)) return 0;
|
||||
}
|
||||
return cd_sig_same(who, p);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,9 @@ extern uint8_t pop_cd_ymin[2][10], pop_cd_ymax[2][10];
|
||||
/* Задели ли прямоугольник (ЭКРАННЫЕ координаты, x1/y1 включительно) то,
|
||||
* что трогали на странице p. Резидент (pop_tile.c). */
|
||||
uint8_t pop_cd_hit(uint8_t p, int x0, int y0, int x1, int y1);
|
||||
/* То же для СЛОТА персонажа: спрайт и накладной, координаты изнутри pop_cd
|
||||
* (см. тело — там про цену пяти аргументов). */
|
||||
uint8_t pop_cd_hit_slot(uint8_t who, uint8_t p);
|
||||
void pop_cd_clear(uint8_t p); /* снять метку страницы целиком */
|
||||
void pop_cd_init(void); /* пустые диапазоны на обеих страницах */
|
||||
void pop_cd_touch(int x, int y, int w, int h);
|
||||
|
||||
@@ -306,6 +306,52 @@ void pop_cd_touch(int x, int y, int w, int h)
|
||||
/* Задел ли прямоугольник (ЭКРАННЫЕ координаты, x1/y1 ВКЛЮЧИТЕЛЬНО) то, что
|
||||
* трогали на странице p. Резидент: зовёт pop_cdraw.c из банка 4 прямым
|
||||
* вызовом, без трамплина. */
|
||||
/* Прямоугольник слота против метки — БЕЗ передачи пяти аргументов.
|
||||
*
|
||||
* pop_cd_hit принимает (p, x0, y0, x1, y1): три последних идут стеком, и
|
||||
* функция целиком уезжает в IX-фрейм — 45 % её тактов уходит на `-n(ix)`
|
||||
* (замер asm 2026-08-19). А зовут её из cd_quiet дважды на слот, то есть
|
||||
* до восьми раз за кадр. Здесь координаты берутся прямо из pop_cd, и
|
||||
* аргументов остаётся два.
|
||||
*
|
||||
* Спрайт и накладной проверяются РАЗДЕЛЬНО — объединённый bbox ловит
|
||||
* касания углом, которых нет (разбор в cd_quiet, pop_cdraw.c). */
|
||||
static int hit_x, hit_y; /* аргументы hit_rect — file-scope, не стек */
|
||||
static uint16_t hit_w, hit_h;
|
||||
static uint8_t hit_p;
|
||||
|
||||
static uint8_t hit_rect(void)
|
||||
{
|
||||
int8_t c0, c1, c;
|
||||
uint8_t ya, yb;
|
||||
int x1 = hit_x + (int)hit_w - 1;
|
||||
int y1 = hit_y + (int)hit_h - 1;
|
||||
if (!hit_w || !hit_h) return 0;
|
||||
if (x1 < 0 || hit_x > 319) return 0;
|
||||
if (y1 < 0 || hit_y > 255) return 0;
|
||||
ya = (uint8_t)(hit_y < 0 ? 0 : hit_y);
|
||||
yb = (uint8_t)(y1 > 255 ? 255 : y1);
|
||||
c0 = (int8_t)((hit_x < 0 ? 0 : hit_x) >> 5);
|
||||
c1 = (int8_t)((x1 > 319 ? 319 : x1) >> 5);
|
||||
for (c = c0; c <= c1; c++)
|
||||
if (ya <= pop_cd_ymax[hit_p][c] && yb >= pop_cd_ymin[hit_p][c]) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t pop_cd_hit_slot(uint8_t who, uint8_t p)
|
||||
{
|
||||
const pop_cdraw_t *s = &pop_cd[who];
|
||||
if (!(pop_cd_dirty & (1 << p))) return 0;
|
||||
hit_p = p;
|
||||
hit_x = s->x[p]; hit_y = s->y[p] + POP_YOFF;
|
||||
hit_w = s->w[p]; hit_h = s->h[p];
|
||||
if (hit_rect()) return 1;
|
||||
if (!s->ovalid[p]) return 0;
|
||||
hit_x = s->ox[p]; hit_y = s->oy[p] + POP_YOFF;
|
||||
hit_w = s->ow[p]; hit_h = s->oh[p];
|
||||
return hit_rect();
|
||||
}
|
||||
|
||||
uint8_t pop_cd_hit(uint8_t p, int x0, int y0, int x1, int y1)
|
||||
{
|
||||
int8_t c0, c1, c;
|
||||
|
||||
Reference in New Issue
Block a user