Габариты спрайтов в байтах: uint16_t -> uint8_t в слоте отрисовки

Замечание пользователя: спрайты наших атласов не крупнее 64x64, а w/h
почти везде были uint16_t.  Это уже записано в памяти проекта
(pop_sprite_size_limits: весь игровой кадр PoP <= 56x63; больше 255 только
восемь полноэкранных подложек титров, а они через слот персонажа не
проходят).

Переведены в uint8_t: w/h, ow/oh, fpw/fph, cw/ch в pop_cdraw_t, параметры
cd_overlay_add и cd_clip_add, локали w/h/vis_w в pop_char_draw и
cd_splash, и чтение габарита из шапки ленты (было двухбайтным сложением
со сдвигом).

Эффект: лёгкая позиция 438 600 -> 438 324 (там персонажи не рисуются,
поэтому почти ничего), тяжёлая — циан 181 404 -> 180 270.  Плюс 24 байта
_DATA на двух слотах.

Скромно, но код от этого не запутаннее, а честнее: тип теперь отражает
реальный диапазон.  Проверено в MAME — бой идёт, хвостов и обрезков нет.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 18:00:19 +03:00
parent 892f005ca5
commit 79bcabde94
2 changed files with 38 additions and 26 deletions
+34 -22
View File
@@ -258,7 +258,7 @@ static int scr_x(int x)
* страницы. Оба мелкие и в одном кадре встречаются редко — их объединение
* дешевле третьего heal-слота. */
static void cd_overlay_add(pop_cdraw_t *s, uint8_t dp, int x, int y,
uint16_t w, uint16_t h)
uint8_t w, uint8_t h)
{
if (!s->ovalid[dp]) {
s->ox[dp] = x; s->oy[dp] = y; s->ow[dp] = w; s->oh[dp] = h;
@@ -273,14 +273,14 @@ static void cd_overlay_add(pop_cdraw_t *s, uint8_t dp, int x, int y,
if (x + (int)w > x1) x1 = x + (int)w;
if (y + (int)h > y1) y1 = y + (int)h;
s->ox[dp] = x0; s->oy[dp] = y0;
s->ow[dp] = (uint16_t)(x1 - x0); s->oh[dp] = (uint16_t)(y1 - y0);
s->ow[dp] = (uint8_t)(x1 - x0); s->oh[dp] = (uint8_t)(y1 - y0);
}
}
/* Добавить прямоугольник в окно fore-клипа слота (объединение «спрайт +
* накладные»): по нему fore-проход возвращает куски тайлов и по нему же
* расширяет перебор колонок/рядов. */
static void cd_clip_add(pop_cdraw_t *s, int x, int y, uint16_t w, uint16_t h)
static void cd_clip_add(pop_cdraw_t *s, int x, int y, uint8_t w, uint8_t h)
{
if (!s->cw) {
s->cx = x; s->cy = y; s->cw = w; s->ch = h;
@@ -292,8 +292,8 @@ static void cd_clip_add(pop_cdraw_t *s, int x, int y, uint16_t w, uint16_t h)
if (y < s->cy) s->cy = y;
if (x + (int)w > x1) x1 = x + (int)w;
if (y + (int)h > y1) y1 = y + (int)h;
s->cw = (uint16_t)(x1 - s->cx);
s->ch = (uint16_t)(y1 - s->cy);
s->cw = (uint8_t)(x1 - s->cx);
s->ch = (uint8_t)(y1 - s->cy);
}
}
@@ -469,7 +469,7 @@ static void cd_splash(pop_cdraw_t *s, uint8_t who, const atlas_t *pages,
const atlas_t *ap;
uint8_t aidx;
const uint8_t *img;
uint16_t w, h;
uint8_t w, h;
int qx = fp_x, qy = obj_y;
int fw = (Char.direction < 0) ? -5 : 5; /* obj_dx_forward(5) */
@@ -491,8 +491,12 @@ static void cd_splash(pop_cdraw_t *s, uint8_t who, const atlas_t *pages,
qx = scr_x(qx + fw); /* calc_screen_x_coord */
img = (const uint8_t *)atlas_image(ap, aidx);
gfx_w0_map(ap->page);
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
/* Габарит БАЙТАМИ: спрайты персонажей и накладных не крупнее 64x64
* (memory pop_sprite_size_limits — весь игровой кадр PoP <= 56x63),
* а 16-битные w/h заставляли SDCC держать их в стековом кадре и
* считать каждое сравнение парой загрузок. */
w = img[0];
h = img[2];
if (w && h) {
int top = qy - (int)h + 1;
uint8_t flip = (uint8_t)(Char.direction >= 0);
@@ -503,15 +507,15 @@ static void cd_splash(pop_cdraw_t *s, uint8_t who, const atlas_t *pages,
if (top + rows > 192) rows = 192 - top;
if (rows <= 0) return;
gfx_set_bank(GFX_BANK_SPRITE);
if (pop_onscreen_cols(qx, top + POP_YOFF, w, (uint16_t)rows))
if (pop_onscreen_cols(qx, top + POP_YOFF, w, (uint8_t)rows))
gfx_blit_cols_part_noclip(qx, top + POP_YOFF, img, flip,
(uint8_t)skip, (uint8_t)rows);
else
gfx_blit_cols_part(qx, top + POP_YOFF, img, flip, skip, rows);
gfx_set_bank(GFX_BANK_NORMAL);
dp = gfx_get_draw_page() & 1;
cd_overlay_add(s, dp, qx, top, w, (uint16_t)rows);
cd_clip_add(s, qx, top, w, (uint16_t)rows);
cd_overlay_add(s, dp, qx, top, w, (uint8_t)rows);
cd_clip_add(s, qx, top, w, (uint8_t)rows);
}
}
@@ -523,7 +527,7 @@ void pop_char_draw(uint8_t who) __banked
const atlas_t *pages;
const uint8_t *img;
uint8_t npages, page, idx, dp, flip, hurt, lskip;
uint16_t w, h, vis_w;
uint8_t w, h, vis_w;
int obj_x, obj_y, fp_x, fwd, top, bx, skip, rows, ct, cr;
int bcut; /* срез СНИЗУ (clip_char в перевёрнутом виде) */
@@ -625,8 +629,12 @@ void pop_char_draw(uint8_t who) __banked
}
gfx_w0_map(vpg);
}
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
/* Габарит БАЙТАМИ: спрайты персонажей и накладных не крупнее 64x64
* (memory pop_sprite_size_limits — весь игровой кадр PoP <= 56x63),
* а 16-битные w/h заставляли SDCC держать их в стековом кадре и
* считать каждое сравнение парой загрузок. */
w = img[0];
h = img[2];
dp = gfx_get_draw_page() & 1;
if (w && h) {
/* Спрайты нарисованы ЛИЦОМ ВЛЕВО (как в оригинале); seg008:864 —
@@ -683,7 +691,7 @@ void pop_char_draw(uint8_t who) __banked
if (cr) {
int avail = cr - bx;
if (avail <= 0) vis_w = 0; /* весь спрайт за косяком */
else if (avail < (int)w) vis_w = (uint16_t)avail;
else if (avail < (int)w) vis_w = (uint8_t)avail;
}
/* КЛИП ТЕНИ СЛЕВА (seg008:1699): на уровне зеркала она может
* показываться ТОЛЬКО СПРАВА от него —
@@ -712,7 +720,7 @@ void pop_char_draw(uint8_t who) __banked
if (lskip) /* тень у зеркала: срез слева */
gfx_blit_cols_part_wx(bx, top + POP_YOFF, img, flip, skip, rows,
lskip, (uint8_t)(vis_w - lskip));
else if (vis_w == w && pop_onscreen_cols(bx, top + POP_YOFF, w, (uint16_t)rows))
else if (vis_w == w && pop_onscreen_cols(bx, top + POP_YOFF, w, (uint8_t)rows))
gfx_blit_cols_part_noclip(bx, top + POP_YOFF, img, flip,
(uint8_t)skip, (uint8_t)rows);
else
@@ -723,9 +731,9 @@ void pop_char_draw(uint8_t who) __banked
/* heal чистит ТОЛЬКО нарисованное: иначе стирается кромка пола над
* срезом (мусор/дыра в кладке на второй странице дабл-буфера). */
s->x[dp] = bx + lskip; s->y[dp] = top;
s->w[dp] = (uint16_t)(vis_w - lskip); s->h[dp] = (uint16_t)rows;
s->w[dp] = (uint8_t)(vis_w - lskip); s->h[dp] = (uint8_t)rows;
s->valid[dp] = (uint8_t)(rows != 0);
if (rows) cd_clip_add(s, bx, top, vis_w, (uint16_t)rows);
if (rows) cd_clip_add(s, bx, top, vis_w, (uint8_t)rows);
s->fpw = w; s->fph = h; /* габарит КАДРА (не обрезанный): */
/* по нему считается футпринт */
}
@@ -806,7 +814,7 @@ void pop_mirror_draw(int clip_top) __banked
const kframe *fr = &kid_frame;
const uint8_t *img;
uint8_t page, idx, flip;
uint16_t w, h, vis_w;
uint8_t w, h, vis_w;
int fwd, obj_x, obj_y, fp_x, bx, top, skip = 0, rows, cl;
uint8_t lskip = 0;
@@ -824,8 +832,12 @@ void pop_mirror_draw(int clip_top) __banked
img = (const uint8_t *)atlas_image(&kidp[page], idx);
gfx_w0_map(kidp[page].page);
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
/* Габарит БАЙТАМИ: спрайты персонажей и накладных не крупнее 64x64
* (memory pop_sprite_size_limits — весь игровой кадр PoP <= 56x63),
* а 16-битные w/h заставляли SDCC держать их в стековом кадре и
* считать каждое сравнение парой загрузок. */
w = img[0];
h = img[2];
if (!w || !h) { gfx_w0_unmap(); return; }
flip = (uint8_t)(Char.direction >= 0);
bx = flip ? obj_x - (int)w : obj_x;
@@ -946,7 +958,7 @@ void pop_hp_draw(void) __banked
if (g_ok && Guard.charid != 0 && Guard.charid != CHARID_4_SKELETON &&
Guard.charid != CHARID_24_MOUSE && gd) {
const uint8_t *img = (const uint8_t *)atlas_image(&gp[0], 0);
uint16_t w, h;
uint8_t w, h;
gfx_w0_map(gp[0].page);
w = (uint16_t)(img[0] | ((uint16_t)img[1] << 8));
h = (uint16_t)(img[2] | ((uint16_t)img[3] << 8));
+4 -4
View File
@@ -51,21 +51,21 @@ typedef struct {
* видео-ОЗУ и своя ОЗУ-копия, поэтому heal обязан стирать спрайт именно
* той страницы, в которую сейчас рисуем */
int x[2], y[2];
uint16_t w[2], h[2];
uint8_t w[2], h[2]; /* габарит: спрайты игры не крупнее 64x64 */
uint8_t valid[2];
/* НАКЛАДНЫЕ спрайты (клинок + брызги урона) — свой прямоугольник, не
* объединение с персонажем: объединение сильно больше суммы двух
* (клинок уходит вперёд-вверх), а heal стоит ровно по площади */
int ox[2], oy[2];
uint16_t ow[2], oh[2];
uint8_t ow[2], oh[2];
uint8_t ovalid[2];
/* габарит кадра для fore-прохода: fpx — ЛОГИЧЕСКАЯ X (до ×8/7),
* fpy — низ спрайта; fpw == 0 — в этом кадре рисовать было нечего */
int fpx, fpy;
uint16_t fpw, fph;
uint8_t fpw, fph;
/* окно fore-клипа слота (объединение «спрайт + накладные»), КОМНАТНЫЙ y */
int cx, cy;
uint16_t cw, ch;
uint8_t cw, ch;
/* straddle: рендерное смещение по ЛОГИЧЕСКОЙ X, когда комната персонажа
* не совпадает с отрисованной (порт xpos_in_drawn_room) */
int render_dx;