libbgi: спрайтовый движок v2 + accel-блит/heal leaf'ы + noclip-путь
Спрайтовая графика поверх accel block-copy (docs/sprite-api-design.md): - Ядро блиттинга: leaf'ы _bgi_blit_rows_raw (dst фикс, только src-страйд) / _bgi_copy_rows_raw (getimage) / _bgi_heal_rows_raw (src==dst). DI один на спрайт (санкция: малый спрайт под одним DI аудио не рвёт); src[0]-фикс снят (точная MAME подавляет CPU-байт триггера записи — на железе перепроверить; для heal был избыточен и снят безусловно). - Общие bracket-free ядра _gfx_blit_full/_gfx_heal_full (полная ширина: клип по экрану + split >256 для putimage) + лин _gfx_blit_sprite/ _gfx_heal_sprite (кадр ≤64, без split, 8-бит w/h) + noclip-варианты (клип-кода нет → полный codegen-win). Имя *_full (не *_clip) — «clip» двусмысленно (sprite-ядра тоже клипуют; различитель — ширина/split). - Движок retained-модели <sprite.h>: sprite_init/update/flip + inline move/frame/show/hide/touch; drawn[2] per-page внутри структуры; кадр — двухпроходно heal ВСЕ -> блит ВСЕ под одной W3-скобкой/банком на проход. - Флаг gfx_sprite_clip(on/off): приложение, само следящее за границами, отключает клип (~+19% на анимации; диспетч пока через if — funcptr далее). - putsprite/movesprite/gfx_blit/putimage(COPY)/getimage переведены на ядро. Тесты: examples/balls (движок, дабл-буфер, boundary-тест клипа), tests/sprites (RAM PASS, клип 4 края, атлас), tests/blitw (trig-leak), tests/spriteclip (hardware-probe: железо НЕ режет за краем -> клип нужен), tests/blitperf, tests/gfxbanks. size-baseline обновлён (53 программы). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
PROJ_ROOT := $(abspath $(CURDIR)/../..)
|
||||
EXAMPLE := spriteclip
|
||||
EXTRA_FLAGS ?= --gfx 256 --memory small
|
||||
include $(PROJ_ROOT)/app.mk
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* spriteclip — ЭКСПЕРИМЕНТ (гипотеза пользователя 2026-07-12): режет ли
|
||||
* ЖЕЛЕЗО спрайт, выведенный за ПРАВЫЙ/НИЖНИЙ край экрана, БЕЗ
|
||||
* программного клипа? Или запись за x>=320 / y>=256 портит соседнюю
|
||||
* память (следующую строку / страницу 1 / верх экрана)?
|
||||
*
|
||||
* Метод: блит 16×16 НЕПРОЗРАЧНОГО белого спрайта мимо клипа — прямым
|
||||
* вызовом leaf'а _bgi_copy_rows_raw (в обход _gfx_blit_clip). Фон —
|
||||
* синий; зелёные линии-маркеры на x=319 и y=255 (граница экрана);
|
||||
* левый край (0..7) и верх (0..7) залиты красным-маркером, чтобы
|
||||
* поймать «заворот» переполнения именно туда.
|
||||
*
|
||||
* Читать скриншот:
|
||||
* - ПРАВЫЙ (спрайт в x=312): если видно только 8 левых колонок белого
|
||||
* (x=312..319), а правых 8 нет И красная левая полоса цела →
|
||||
* железо режет по правому краю. Если правые 8 колонок «завернулись»
|
||||
* белым в x=0..7 (поверх красного) или появился мусор — НЕ режет,
|
||||
* клип обязателен.
|
||||
* - НИЖНИЙ (спрайт в y=250): если видно 6 строк белого (y=250..255),
|
||||
* а строк за 256 нет И красная верхняя полоса цела → железо режет по
|
||||
* нижнему. Если белое всплыло сверху (y=0..) — Port_Y завернулся.
|
||||
* - УГОЛ (x=312,y=250): комбинация.
|
||||
*
|
||||
* НЕ для CI-регресса — разовый hardware-probe (и в MAME, и на железе).
|
||||
*/
|
||||
|
||||
#include <graphics.h>
|
||||
#include <gfx.h>
|
||||
#include <conio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Внутренние символы libbgi (глобальны в bgi256.lib) — тянем напрямую
|
||||
* ради no-clip блита. Обычному коду так делать НЕ надо (есть gfx_blit). */
|
||||
extern void _bgi_begin(void);
|
||||
extern void _bgi_end(void);
|
||||
extern void _bgi_copy_rows_raw(const uint8_t *src, uint8_t *dst,
|
||||
uint8_t w, uint8_t h,
|
||||
int dstride, int sstride, uint8_t y0);
|
||||
extern uint16_t _gfx_addr_base;
|
||||
|
||||
#define BW 16
|
||||
static uint8_t sprite[4 + BW * BW];
|
||||
|
||||
static void build_sprite(void)
|
||||
{
|
||||
uint8_t *p = sprite;
|
||||
int i;
|
||||
|
||||
*p++ = BW; *p++ = 0; *p++ = BW; *p++ = 0;
|
||||
for (i = 0; i < BW * BW; i++)
|
||||
*p++ = WHITE; /* непрозрачный: каждый байт пишется */
|
||||
}
|
||||
|
||||
/* Блит БЕЗ клипа: адрес = base + x, Port_Y стартует с y, строки шагают
|
||||
* Port_Y'ем (dstride 0). x/y могут выходить за экран — в этом и суть. */
|
||||
static void blit_noclip(int x, int y)
|
||||
{
|
||||
uint8_t *dst = (uint8_t *)(_gfx_addr_base + x);
|
||||
|
||||
gfx_set_bank(GFX_BANK_NORMAL);
|
||||
_bgi_begin();
|
||||
_bgi_copy_rows_raw(sprite + 4, dst, BW, BW, 0, BW, (uint8_t)y);
|
||||
_bgi_end();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
build_sprite();
|
||||
initgraph();
|
||||
|
||||
/* Фон синий. */
|
||||
setfillstyle(SOLID_FILL, BLUE);
|
||||
bar(0, 0, 319, 255);
|
||||
|
||||
/* Красные маркер-полосы: левые 8 колонок и верхние 8 строк —
|
||||
* сюда «завернётся» переполнение вправо/вниз, если железо не режет. */
|
||||
setfillstyle(SOLID_FILL, RED);
|
||||
bar(0, 0, 7, 255);
|
||||
bar(0, 0, 319, 7);
|
||||
|
||||
/* Зелёные маркеры границы экрана. */
|
||||
setcolor(GREEN);
|
||||
line(319, 0, 319, 255);
|
||||
line(0, 255, 319, 255);
|
||||
|
||||
/* Sanity: клипнутый putsprite тем же спрайтом в безопасном месте. */
|
||||
putsprite(140, 120, sprite);
|
||||
|
||||
/* Эксперимент — три no-clip блита за края: */
|
||||
blit_noclip(312, 100); /* правый: x+16=328, 8 колонок за 320 */
|
||||
blit_noclip(100, 250); /* нижний: y+16=266, 10 строк за 256 */
|
||||
blit_noclip(312, 250); /* угол: и вправо, и вниз */
|
||||
|
||||
getch();
|
||||
closegraph();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user