Files
Sprinter-SDCC/tests/bgi_img/bgi_img.c
T
snark13 a823e7ee9c libbgi: блочные AND/OR/XOR акселератора (блит строками и колонками)
Акселератор умеет не только копировать блок, но и совмещать его с
приёмником: опкод `and/or/xor (hl)` между триггерами чтения и записи
переводит внутренний автомат из «буфер := память» в «буфер <op>= память».
Операция ортогональна направлению (гориз. LD L,L / верт. LD A,A), значит
одинаково работает и для row-major картинок, и для column-major спрайтов
персонажей с бесплатным флипом.

Полный набор, по образцу существующего копирующего:
- ядра bgi256/_bgi_blit_rows_op_raw.c и _bgi_blit_cols_op_raw.c;
- строками: gfx_blit_op / gfx_blit_part_op (через _gfx_blit_full_op);
- колонками: gfx_blit_cols_op / gfx_blit_cols_part_wx_op (skip/rows/
  skipw/maxw и flip — как у копирующего близнеца);
- putimage(XOR/OR/AND_PUT) переведён на accel, попиксельным остался
  только NOT_PUT — закрыт пункт 2d-1 docs/TODO.md.

Одна функция на три операции: опкод патчится SMC, как размер блока и
страйд, — ветвления в цикле нет.  Колоночный путь дороже строкового на
один OUT Port_Y: вертикальный op-burst шагает Port_Y, и перед записью
его надо вернуть на верх колонки (STOP обязателен — иначе fetch операнда
OUT перезапустит burst, memory/accel_operand_fetch_retrigger).

Две оговорки (в шапках модулей):
- операция ЧИТАЕТ ОЗУ-копию экрана, а не видео-ОЗУ, поэтому при банках
  0x54/0x5C совмещается с чистым фоном, а не с нарисованным поверх;
- аппаратная прозрачность #FF совместима с AND (нейтраль) и OR (#FF|bg =
  #FF, запись подавляется), но НЕ с XOR: там источник обязан хранить
  прозрачный пиксель как 0x00.

Проверка: tests/accop (новый) — 8/8 PASS в MAME, побайтно, источник с
разными значениями по строкам И колонкам + рамка вокруг; tests/bgi_img
получил две байтовые самопроверки (COPY==источник, XOR дважды == фон),
обе PASS.  make size-check: роста нет (эталон принят заново — kbdpoll
+63 Б приехал из прошлой сессии, воспроизводится и без этих правок).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 15:03:47 +03:00

155 lines
6.4 KiB
C
Raw 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.
/*
* bgi_img — тест спрайтов BGI: getimage / putimage / imagesize
* (режим 320×256×256, --gfx 256).
*
* Что проверяем:
* 1. imagesize() совпадает с реальным размером буфера (self-check —
* при расхождении рисуется красная плашка "SIZE MISMATCH").
* 2. getimage() снимает прямоугольник экрана в буфер (заголовок
* w,h + w*h байт).
* 3. putimage() кладёт образ всеми пятью операциями COPY/XOR/OR/AND/
* NOT поверх серого фона — визуально видно разницу операций.
* 4. XOR дважды по одному месту восстанавливает фон (классический
* признак корректного спрайтового XOR).
*
* Прогон в MAME визуальный: см. что источник и его COPY-копия
* идентичны (в т.ч. красный маркер в левом-верхнем углу — ловит
* зеркалирование), а XOR-дважды не оставляет следа на фоне.
*
* 2026-08-11: XOR/OR/AND_PUT переведены с попиксельного цикла на блочные
* операции акселератора (gfx_blit_part_op), поэтому к визуальной проверке
* добавлены ДВЕ БАЙТОВЫЕ (PASS/FAIL на экране) — глазами тут промах на
* пиксель или уехавший Port_Y не поймать:
* P1 COPY == источник побайтно (клип/адресация не сдвинули образ);
* P2 XOR дважды == чистый фон побайтно (op-burst читает ровно тот байт
* приёмника, поверх которого потом пишет).
* Механика самих блочных операций проверяется отдельно — tests/accop.
*/
#include <graphics.h>
#include <stdint.h>
/* Габариты спрайта-источника. Из них же считаем и рект, и буфер —
* так imagesize() и sizeof(buf) обязаны сойтись. */
#define SPR_L 16
#define SPR_T 28
#define SPR_W 40
#define SPR_H 32
/* Буфер образа: 4 байта заголовка (w,h) + по байту на пиксель. */
static uint8_t sprite[4 + SPR_W * SPR_H];
/* Нарисовать узнаваемый ассиметричный образ в (SPR_L,SPR_T). */
static void draw_source(void)
{
int l = SPR_L, t = SPR_T;
int r = l + SPR_W - 1, b = t + SPR_H - 1;
setfillstyle(SOLID_FILL, LIGHTBLUE);
bar(l, t, r, b); /* фон образа */
setcolor(YELLOW);
circle(l + SPR_W / 2, t + SPR_H / 2, 10);
setcolor(WHITE);
line(l, t, r, b); /* диагональ */
/* Красный маркер в левом-верхнем углу — детектор ориентации. */
setfillstyle(SOLID_FILL, LIGHTRED);
bar(l, t, l + 5, t + 5);
setcolor(WHITE);
rectangle(l - 1, t - 1, r + 1, b + 1); /* рамка вокруг источника */
}
/* Прямоугольник (x0,y0,w,h) совпадает с прямоугольником (x1,y1,w,h)? */
static uint8_t rect_eq(int x0, int y0, int x1, int y1, int w, int h)
{
int cx, cy;
for (cy = 0; cy < h; cy++)
for (cx = 0; cx < w; cx++)
if (getpixel(x0 + cx, y0 + cy) != getpixel(x1 + cx, y1 + cy))
return 0;
return 1;
}
static void say(int x, int y, const char *s, uint8_t ok)
{
setcolor(ok ? LIGHTGREEN : LIGHTRED);
outtextxy(x, y, s);
outtextxy(x + textwidth((char *)s) + 4, y, ok ? "PASS" : "FAIL");
}
int main(void)
{
static const int ops[5] = { COPY_PUT, XOR_PUT, OR_PUT, AND_PUT, NOT_PUT };
static const char *names[5] = { "COPY", "XOR", "OR", "AND", "NOT" };
uint8_t p_copy, p_xor2;
int i, x;
int sl = SPR_L, st = SPR_T;
int sr = SPR_L + SPR_W - 1, sb = SPR_T + SPR_H - 1;
initgraph();
cleardevice();
setcolor(WHITE);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 1);
outtextxy(80, 6, "getimage/putimage test");
/* --- источник --- */
outtextxy(SPR_L, 18, "src");
draw_source();
/* --- imagesize() self-check --- */
if (imagesize(sl, st, sr, sb) != (unsigned)sizeof(sprite)) {
setfillstyle(SOLID_FILL, LIGHTRED);
bar(80, 90, 240, 100);
setcolor(WHITE);
outtextxy(84, 92, "SIZE MISMATCH");
}
/* --- снимаем образ --- */
getimage(sl, st, sr, sb, sprite);
/* --- пять операций putimage поверх серого фона --- */
for (i = 0; i < 5; i++) {
x = 16 + i * 60;
setcolor(WHITE);
outtextxy(x, 108, names[i]);
setfillstyle(SOLID_FILL, LIGHTGRAY); /* общий фон под все ops */
bar(x, 120, x + SPR_W - 1, 120 + SPR_H - 1);
putimage(x, 120, sprite, ops[i]);
}
/* P1: COPY-копия (x = 16, первая в ряду) обязана совпасть с источником
* побайтно — ловит сдвиг на пиксель и зеркалирование. */
p_copy = rect_eq(16, 120, sl, st, SPR_W, SPR_H);
/* --- XOR дважды = восстановление фона --- */
setcolor(WHITE);
outtextxy(16, 176, "XOR x2 -> restores bg (patch stays clean):");
setfillstyle(SOLID_FILL, GREEN);
bar(16, 190, 16 + SPR_W - 1, 190 + SPR_H - 1);
putimage(16, 190, sprite, XOR_PUT); /* наложили */
putimage(16, 190, sprite, XOR_PUT); /* сняли */
/* Рядом — тот же зелёный фон нетронутым, для сравнения. */
setfillstyle(SOLID_FILL, GREEN);
bar(80, 190, 80 + SPR_W - 1, 190 + SPR_H - 1);
setcolor(WHITE);
outtextxy(130, 202, "<- these two must match ->");
/* P2: наложенный и снятый XOR не оставил следа — сравниваем с
* нетронутым зелёным эталоном справа. */
p_xor2 = rect_eq(16, 190, 80, 190, SPR_W, SPR_H);
say(16, 228, "P1 COPY==src:", p_copy);
say(16, 240, "P2 XORx2==bg:", p_xor2);
for (;;) { }
}