PoP roomtest: клинок в атласе целиком + раздельный heal накладных спрайтов
Меч в оригинале ОДИН на всех: и Кид, и страж рисуют клинок из chtab_0 (add_sword_to_objtable, seg006:1798). Раньше sword.atl содержал только кадры подъёма/ножен (sword_tbl 35..42), поэтому у стража меча не было видно вовсе. - pop_pack_kid.py пакует chtab_0 целиком (id 0..33, 5168 Б), индекс в атласе = id; - pop_extract_kid_data.py вытаскивает sword_tbl (53 строки) в kid_data.h макро-инициализаторами — таблица ложится в один TU, а не в каждый; - pop_sword_draw (pop_kid.c) — общая точка отрисовки клинка с полным условием оригинала (кадры 229..237 ИЛИ меч обнажён ИЛИ живой страж); зовут и kid_draw, и pop_guard_draw. Раздельный heal накладных спрайтов. Клинок и брызги урона раньше объединялись в один прямоугольник с персонажем, а объединение почти вдвое больше суммы двух (клинок уходит вперёд-вверх) — heal же стоит ровно по площади. Теперь у накладных свой прямоугольник и свой gfx_heal, а объединение осталось ТОЛЬКО для окна fore-клипа: там это 4 сравнения без рисования, но покрыть клинок обязано, иначе он полезет поверх столба. Отладка: DEBUG_SWORD_ROOM — Киду выдаётся меч при входе в комнату 3 (там страж), чтобы не бегать за ним в комнату 15. Бюджет (225 кадров, комната 3): 415 284 – 416 370 = 0.966–0.968 кадра. Против 384 168 – 384 636 до этого шага, то есть +31 700. Разложение по фазам (медианы): process_trobs 83 190, pop_guard_draw 92 483 (спрайт 28 763 + клинок 23 820 + fore_over_char 39 906), kid_draw 59 089, fore поверх Кида + борта 47 483, heal 40 068, логика 76 338, ввод 13 050. Видно, что клинок 21x8 стоит почти как спрайт стража — это фиксированные накладные расходы клипающего блита, а не пиксели; лечится noclip-путём для column-major (см. gfx_blit_noclip_fast). Отдельным шагом. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
#include <gfx.h>
|
||||
#include <sprite.h>
|
||||
#include "pop_guard.h"
|
||||
#include "pop_kid.h" /* pop_sword_draw — клинок общий с Кидом */
|
||||
#include "pop_bg.h" /* POP_YOFF, pop_fore_over_char */
|
||||
#include "kid_data.h"
|
||||
|
||||
@@ -29,6 +30,13 @@ static int gx_l[2], gy_l[2];
|
||||
static uint16_t gw_l[2], gh_l[2];
|
||||
static uint8_t gvalid[2];
|
||||
|
||||
/* Клинок — ОТДЕЛЬНЫМ прямоугольником, не объединением со стражем: объединение
|
||||
* почти вдвое больше суммы двух (клинок уходит вперёд-вверх), а heal стоит
|
||||
* ровно по площади. Объединение считаем только для окна fore-клипа. */
|
||||
static int sx_l[2], sy_l[2];
|
||||
static uint16_t sw_l[2], sh_l[2];
|
||||
static uint8_t svalid[2];
|
||||
|
||||
int pop_guard_load(void) __banked
|
||||
{
|
||||
static const char *const names[GUARD_PAGES] = {
|
||||
@@ -54,15 +62,20 @@ void pop_guard_heal(void) __banked
|
||||
{
|
||||
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]);
|
||||
gvalid[p] = 0;
|
||||
if (svalid[p]) gfx_heal(sx_l[p], sy_l[p] + POP_YOFF, sw_l[p], sh_l[p]);
|
||||
gvalid[p] = svalid[p] = 0;
|
||||
}
|
||||
|
||||
void pop_guard_draw(void) __banked
|
||||
{
|
||||
int obj_x, obj_y, top, fwd, fp_x, bx0 = 0, top0 = 0;
|
||||
int obj_x, obj_y, top, fwd, fp_x;
|
||||
uint8_t page, idx, p, flip;
|
||||
const uint8_t *img;
|
||||
uint16_t w, h;
|
||||
/* Окно fore-клипа — по ОБЪЕДИНЁННОМУ габариту «страж + клинок»; сам
|
||||
* футпринт (pop_fore_over_char) считается по спрайту стража, поэтому
|
||||
* w/h ниже НЕ трогаем. */
|
||||
int clip_x = 0, clip_y = 0; uint16_t clip_w = 0, clip_h = 0;
|
||||
|
||||
if (!g_ok || Guard.charid == 0 || pop_gframe.image == 255) return;
|
||||
/* load_frame_to_obj (seg008:1728) — та же математика, что у Kid. */
|
||||
@@ -85,17 +98,41 @@ void pop_guard_draw(void) __banked
|
||||
flip = (uint8_t)(Guard.direction >= 0); /* спрайты нарисованы влево */
|
||||
if (flip) bx -= (int)w;
|
||||
top = obj_y - (int)h + 1;
|
||||
bx0 = bx; top0 = top;
|
||||
p = gfx_get_draw_page() & 1;
|
||||
gfx_set_bank(GFX_BANK_SPRITE);
|
||||
gfx_blit_cols_part(bx, top + POP_YOFF, img, flip, 0, 0);
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
gx_l[p] = bx; gy_l[p] = top; gw_l[p] = w; gh_l[p] = h; gvalid[p] = 1;
|
||||
clip_x = bx; clip_y = top; clip_w = w; clip_h = h;
|
||||
}
|
||||
/* Клинок стража — тот же chtab_0, что у Кида (add_sword_to_objtable,
|
||||
* seg006:1798): у ЖИВОГО стража меч в руке всегда. Свой прямоугольник
|
||||
* heal; окно fore-клипа — объединение (без него клинок полез бы поверх
|
||||
* переднего столба). */
|
||||
{
|
||||
int sx, sy; uint16_t sw, sh;
|
||||
if (pop_sword_draw(&Guard, &pop_gframe, obj_x, obj_y,
|
||||
&sx, &sy, &sw, &sh)) {
|
||||
p = gfx_get_draw_page() & 1;
|
||||
sx_l[p] = sx; sy_l[p] = sy; sw_l[p] = sw; sh_l[p] = sh;
|
||||
svalid[p] = 1;
|
||||
if (!clip_w) {
|
||||
clip_x = sx; clip_y = sy; clip_w = sw; clip_h = sh;
|
||||
} else {
|
||||
int x1 = clip_x + (int)clip_w, y1 = clip_y + (int)clip_h;
|
||||
if (sx < clip_x) clip_x = sx;
|
||||
if (sy < clip_y) clip_y = sy;
|
||||
if (sx + (int)sw > x1) x1 = sx + (int)sw;
|
||||
if (sy + (int)sh > y1) y1 = sy + (int)sh;
|
||||
clip_w = (uint16_t)(x1 - clip_x);
|
||||
clip_h = (uint16_t)(y1 - clip_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
gfx_w0_unmap();
|
||||
/* Окно fore-слоя = прямоугольник стража (см. pop_bg.c, fclip_on):
|
||||
* без него проход возвращал ЦЕЛЫЕ тайлы — 432 К тактов на кадр. */
|
||||
pop_fore_set_clip(bx0, top0 + POP_YOFF, (int)w, (int)h);
|
||||
/* Окно fore-слоя = прямоугольник стража с клинком (см. pop_bg.c,
|
||||
* fclip_on): без него проход возвращал ЦЕЛЫЕ тайлы — 432 К тактов. */
|
||||
pop_fore_set_clip(clip_x, clip_y + POP_YOFF, (int)clip_w, (int)clip_h);
|
||||
/* Передние грани тайлов ПОВЕРХ стража: в оригинале персонаж — запись
|
||||
* midtable, а foretable рисуется после всех midtable-записей, поэтому
|
||||
* колонна/кромка пола перекрывает ЛЮБОГО персонажа, не только Kid
|
||||
|
||||
Reference in New Issue
Block a user