Files
Sprinter-SDCC/tests/spriteclip/spriteclip.c
T
snark13 72ce66275e 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>
2026-07-12 21:51:52 +03:00

98 lines
4.4 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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;
}