Files
Sprinter-SDCC/libbgi/include/graphics.h
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

249 lines
14 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.
/*
* graphics.h — Turbo-C-совместимый (функционально) BGI-слой для Sprinter.
*
* Слой поверх низкоуровневого gfx.h. Состояние (текущий цвет, позиция,
* границы экрана) хранится внутри — как в оригинальном BGI, где функции
* рисуют «текущим» цветом от «текущей» позиции.
*
* РЕЖИМ фиксируется на этапе ЛИНКОВКИ выбором driver-библиотеки:
* sprinter-cc --gfx 256 → 320×256×256 (эта версия)
* (--gfx 16 → 640×256×16 будет позже; API идентичен, менять код не надо)
* Одновременно два режима использовать нельзя.
*
* Отличия от Turbo-C (функциональная, а не буквальная совместимость):
* - initgraph() без аргументов-указателей на драйвер: драйвер задан
* линковкой, грузить .bgi-файл с диска не нужно.
* - в 256-режиме initgraph() загружает EGA-совместимые цвета 0..15 в
* палитру, так что setcolor(RED) и т.п. работают как в Turbo-C;
* индексы 16..255 свободны под свои цвета (getmaxcolor() = 255).
* - fill-паттерны/стили линий/стили текста — Фаза 2 (пока bar/bar-подобное
* заливается текущим цветом, линии сплошные, текст 8×8).
*/
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include <stdint.h>
/* ---- Стандартные EGA/VGA цвета (индексы палитры 0..15) ------------ */
enum {
BLACK = 0, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY,
DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA,
YELLOW, WHITE
};
/* 8-битный цвет (индекс палитры). При смене формата достаточно поменять
* один typedef — все public-функции используют этот тип. */
typedef uint8_t color_t;
/* ---- Коды graphresult() ------------------------------------------ */
#define grOk 0
#define grNoInitGraph (-1)
#define grError (-11)
/* ---- Внутреннее состояние BGI ------------------------------------- *
* НЕ трогать напрямую — только через функции ниже. Объявлено здесь,
* чтобы тривиальные аксессоры были inline (без call/ret и без
* .rel-модуля на каждый геттер). Именно `inline` БЕЗ static: SDCC
* инлайнит вызов и НЕ эмитит standalone-тело (static inline эмитил бы
* мёртвую копию в каждый включивший модуль — проверено 2026-07-10);
* если SDCC когда-нибудь откажется инлайнить — будет громкая ошибка
* линковки, не тихая деградация. Хранилище — libbgi/common/
* _bgi_state.c и _bgi_fill_state.c. */
extern uint8_t _bgi_fg, _bgi_bg;
extern int _bgi_cx, _bgi_cy;
extern int _bgi_maxx, _bgi_maxy, _bgi_maxcolor;
extern int _bgi_result;
extern uint8_t _bgi_fill_pattern, _bgi_fill_color;
/* ---- Setup / teardown -------------------------------------------- */
/* Перейти в графический режим (для этой либы — 320×256×256), загрузить
* EGA-палитру, сбросить состояние: цвет = WHITE, фон = BLACK, текущая
* позиция = (0,0). Предыдущий видеорежим запоминается для closegraph. */
void initgraph(void);
/* Вернуться в текстовый режим, действовавший до initgraph(). */
void closegraph(void);
/* Код последней ошибки; вызов сбрасывает его в grOk (как в BGI). */
inline int graphresult(void)
{
int r = _bgi_result;
_bgi_result = grOk;
return r;
}
/* Очистить экран фоновым цветом и вернуть позицию в (0,0). */
void cleardevice(void);
/* ---- Границы и цвета --------------------------------------------- */
inline int getmaxx(void) { return _bgi_maxx; } /* 319 */
inline int getmaxy(void) { return _bgi_maxy; } /* 255 */
inline color_t getmaxcolor(void) { return (color_t)_bgi_maxcolor; } /* 255 */
/* текущий цвет рисования */
inline void setcolor(color_t color) { _bgi_fg = (uint8_t)color; }
inline color_t getcolor(void) { return _bgi_fg; }
/* фоновый цвет (для cleardevice/текста) */
inline void setbkcolor(color_t color) { _bgi_bg = (uint8_t)color; }
inline color_t getbkcolor(void) { return _bgi_bg; }
/* ---- Точки ------------------------------------------------------- */
void putpixel(int x, int y, color_t color);
color_t getpixel(int x, int y);
/* ---- Текущая позиция и линии ------------------------------------- */
/* задать текущую позицию (CP) */
inline void moveto(int x, int y) { _bgi_cx = x; _bgi_cy = y; }
/* сдвинуть CP относительно */
inline void moverel(int dx, int dy) { _bgi_cx += dx; _bgi_cy += dy; }
inline int getx(void) { return _bgi_cx; }
inline int gety(void) { return _bgi_cy; }
void lineto(int x, int y); /* линия CP→(x,y), CP := (x,y) */
void linerel(int dx, int dy); /* линия CP→CP+(dx,dy), CP сдвигается */
void line(int x1, int y1, int x2, int y2); /* линия, CP не меняет */
/* ---- Фигуры ------------------------------------------------------ */
void rectangle(int left, int top, int right, int bottom); /* контур */
void bar(int left, int top, int right, int bottom); /* заливка */
void circle(int x, int y, int radius); /* окружность */
/* Дуги/эллипсы: угол в градусах, 0°=восток, против часовой стрелки.
* Полный эллипс — ellipse(x,y,0,360,xr,yr). */
void arc(int x, int y, int stangle, int endangle, int radius);
void ellipse(int x, int y, int stangle, int endangle,
int xradius, int yradius);
/* Ломаная по numpoints точкам {x0,y0,x1,y1,…}; НЕ замыкается сама. */
void drawpoly(int numpoints, const int *polypoints);
/* ---- Стиль линий ------------------------------------------------- *
* Действует на line/lineto/linerel/rectangle/drawpoly. USERBIT_LINE
* использует 16-битный upattern. thickness: NORM_WIDTH или THICK_WIDTH.
* (Окружности/дуги пока всегда сплошные 1px — упрощение.) */
enum { SOLID_LINE = 0, DOTTED_LINE, CENTER_LINE, DASHED_LINE, USERBIT_LINE };
#define NORM_WIDTH 1
#define THICK_WIDTH 3
struct linesettingstype { int linestyle; unsigned upattern; int thickness; };
void setlinestyle(int linestyle, unsigned upattern, int thickness);
void getlinesettings(struct linesettingstype *lineinfo);
/* ---- Заливки ----------------------------------------------------- *
* Стиль заливки — паттерн (8×8) + цвет; действует на bar/bar3d/
* fillpoly/fillellipse. SOLID_FILL заполняет сплошняком, EMPTY_FILL —
* фоновым цветом. USER_FILL пока трактуется как SOLID. */
enum {
EMPTY_FILL = 0, SOLID_FILL, LINE_FILL, LTSLASH_FILL, SLASH_FILL,
BKSLASH_FILL, LTBKSLASH_FILL, HATCH_FILL, XHATCH_FILL,
INTERLEAVE_FILL, WIDE_DOT_FILL, CLOSE_DOT_FILL, USER_FILL
};
struct fillsettingstype { int pattern; color_t color; };
inline void setfillstyle(int pattern, color_t color)
{
_bgi_fill_pattern = (uint8_t)pattern;
_bgi_fill_color = (uint8_t)color;
}
void getfillsettings(struct fillsettingstype *fillinfo);
/* bar — залитый прямоугольник (текущий стиль заливки, без рамки). */
/* bar3d — 3D-брусок: перёд залит стилем заливки, рёбра — тек. цветом;
* topflag != 0 рисует верхнюю грань. */
void bar3d(int left, int top, int right, int bottom, int depth, int topflag);
/* fillpoly — залитый многоугольник (авто-замыкается); контур тек.
* цветом, нутро — стилем заливки. Вогнутые заполняются по выпуклой
* оболочке строк (min/max X на строку) — упрощение. */
void fillpoly(int numpoints, const int *polypoints);
/* fillellipse — залитый эллипс (полуоси xradius,yradius). */
void fillellipse(int x, int y, int xradius, int yradius);
/* floodfill — заливка области, содержащей (x,y), текущим стилем до
* границы цвета border. Заливка сплошная цветом заливки (паттерн в
* floodfill пока не применяется — упрощение). */
void floodfill(int x, int y, int border);
/* pieslice — залитый сектор круга; sector — эллиптический сектор.
* Контур (дуга + два радиуса) тек. цветом, нутро — стилем заливки.
* Для секторов >180° возможен перелив в «выемку» (min/max по строке). */
void pieslice(int x, int y, int stangle, int endangle, int radius);
void sector(int x, int y, int stangle, int endangle,
int xradius, int yradius);
/* ---- Растровые образы (спрайты) ---------------------------------- *
* Формат буфера: 2×uint16 (ширина, высота в пикселях) + пиксели
* построчно (1 байт/пиксель в режиме 256). Буфер выделяет вызывающий
* размером imagesize(). */
enum { COPY_PUT = 0, XOR_PUT, OR_PUT, AND_PUT, NOT_PUT };
/* Байт под образ прямоугольника (left,top)-(right,bottom) включительно.
* ВНИМАНИЕ: результат — 16-бит unsigned; образы ≥64 КБ не поддержаны. */
unsigned imagesize(int left, int top, int right, int bottom);
/* Сохранить прямоугольник экрана в bitmap (размер = imagesize()). */
void getimage(int left, int top, int right, int bottom, void *bitmap);
/* Вывести образ левым-верхним углом в (left,top) операцией op
* (COPY/XOR/OR/AND/NOT_PUT). COPY_PUT — через акселератор, с
* клиппингом по экрану и текущим банком gfx_set_bank (см. <gfx.h>);
* XOR/OR/AND/NOT — по-пиксельно, без клиппинга. */
void putimage(int left, int top, const void *bitmap, int op);
/* ---- Спрайты (аппаратная прозрачность; docs/sprite-api-design.md) - *
* Спрайт — тот же буфер getimage-формата; прозрачные точки в данных =
* байты 0xFF (GFX_TRANSPARENT). Прозрачность и сохранность фона
* обеспечивает железо (банк GFX_BANK_SPRITE = 0x5C): прозрачные байты
* не записываются, ОЗУ-копия фона не трогается — стирание без
* save-буфера через gfx_heal (см. <gfx.h>).
* ВАЖНО: фон/сцену рисовать ОБЫЧНЫМ банком (0x50) — то, что нарисовано
* при активном бите 2 (0x54/0x5C), в ОЗУ-копию не попадает и heal
* вернёт то, что лежало под ним. */
/* Вывести спрайт в (x,y): банк на время вызова — GFX_BANK_SPRITE,
* затем прежний. Клиппится по экрану. */
void putsprite(int x, int y, const void *img);
/* Переместить спрайт: восстановить фон под (oldx,oldy) (gfx_heal по
* размерам img) и вывести спрайт в (x,y). Перекрытие старой и новой
* позиций безопасно (heal читает фон из ОЗУ-копии). */
void movesprite(int oldx, int oldy, int x, int y, const void *img);
/* ---- Текст ------------------------------------------------------- *
* Шрифт 8×8 (системный). Рисуется текущим цветом на фоновом. */
void outtextxy(int x, int y, const char *text); /* в (x,y), CP не меняет */
void outtext(const char *text); /* в CP; CP сдвигается вправо */
/* ---- Стиль текста ------------------------------------------------ *
* Поддержан только DEFAULT_FONT (8×8, растровый); charsize 1..10 —
* целочисленный масштаб; direction — HORIZ_DIR или VERT_DIR (поворот
* 90° против часовой). Фон текста прозрачный (рисуется только цвет). */
enum { DEFAULT_FONT = 0, TRIPLEX_FONT, SMALL_FONT, SANS_SERIF_FONT,
GOTHIC_FONT };
enum { HORIZ_DIR = 0, VERT_DIR = 1 };
struct textsettingstype {
int font;
int direction;
int charsize;
int horiz;
int vert;
};
void settextstyle(int font, int direction, int charsize);
void gettextsettings(struct textsettingstype *textinfo);
int textwidth(const char *text);
int textheight(const char *text);
#endif