libc: BGI Фаза 2a — arc/ellipse/drawpoly

Дуги/эллипсы через целочисленную тригонометрию Q7 (_bgi_trig.c, ×128) +
общий рисователь полилинией (_bgi_arc_draw.c). arc(x,y,st,end,r),
ellipse(x,y,st,end,xr,yr), drawpoly(n,pts). Проверено в MAME (tests/
bgitest): окружность/эллипс/дуга/полигон рисуются корректно.

ВАЖНО: тригонометрию считаем в int (Q7), НЕ через (long)…>>8 — первая
версия на 32-бит арифметике рисовала эллипс прямоугольником (SDCC/z80
криво собирает 32-бит; см. memory/avoid_32bit_arith_z80). Q7 даёт
радиус×значение ≤ 255×128 < 32767 — всё влезает в 16 бит.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-08 15:50:00 +03:00
parent e761d21505
commit 5a48f7fafb
9 changed files with 162 additions and 29 deletions
+11
View File
@@ -42,6 +42,17 @@ unsigned _bgi_read(int x, int y);
void _bgi_begin(void);
void _bgi_end(void);
void _bgi_plot_raw(int x, int y, uint8_t color);
/* ---- Тригонометрия для дуг (_bgi_trig.c) ------------------------- *
* Угол в градусах; результат sin/cos × 128 (Q7 — чтобы радиус×значение
* влезало в int без 32-бит арифметики). */
int _bgi_sin128(int deg);
int _bgi_cos128(int deg);
/* Общий рисователь дуги/контура эллипса (_bgi_arc_draw.c): полилиния
* по точкам от stangle до endangle с полуосями xr,yr вокруг (cx,cy). */
void _bgi_ellipse_arc(int cx, int cy, int stangle, int endangle,
int xr, int yr, uint8_t color);
void _bgi_hspan(int x, int y, int len, uint8_t color);
void _bgi_lineseg(int x0, int y0, int x1, int y1, uint8_t color);
void _bgi_fillrect(int x, int y, int w, int h, uint8_t color);
+33
View File
@@ -0,0 +1,33 @@
/*
* _bgi_ellipse_arc — контур дуги/эллипса полилинией.
*
* Точки параметризованы углом (BGI: 0°=восток, против часовой, ось Y
* вниз): px = cx + xr*cos(a), py = cy - yr*sin(a). Соседние выборки
* соединяются отрезками — контур сплошной при любом радиусе.
*
* Тригонометрия в Q7 (×128): xr*cos128 ≤ 255×128 < 32767, помещается в
* int — БЕЗ 32-битной арифметики (её SDCC/Z80 собирает криво: раньше
* эллипс через (long)…>>8 рисовался прямоугольником).
*/
#include "_bgi.h"
void _bgi_ellipse_arc(int cx, int cy, int stangle, int endangle,
int xr, int yr, uint8_t color)
{
int a, x, y, px, py, first;
if (endangle < stangle) endangle += 360; /* дуга через 0° */
px = 0;
py = 0;
first = 1;
for (a = stangle; a <= endangle; a++) {
x = cx + ((xr * _bgi_cos128(a)) >> 7);
y = cy - ((yr * _bgi_sin128(a)) >> 7);
if (!first) _bgi_lineseg(px, py, x, y, color);
px = x;
py = y;
first = 0;
}
}
+43
View File
@@ -0,0 +1,43 @@
/*
* _bgi_trig — целочисленная тригонометрия для дуг/эллипсов BGI.
*
* Угол в градусах (Turbo-C); sin/cos масштабированы на 128 (Q7):
* _bgi_sin128(90) = 128. Масштаб 128 (а не 256) выбран так, чтобы
* произведение радиус×значение помещалось в 16-бит int для любого
* экранного радиуса (255×128 = 32640 < 32767) — и НЕ приходилось
* трогать 32-битную арифметику, которую SDCC/Z80 собирает криво
* (см. memory/avoid_32bit_arith_z80; ловили эллипс-в-прямоугольник).
*/
#include "_bgi.h"
/* sin(0°..90°) × 128. */
static const int _bgi_sintab[91] = {
0, 2, 4, 7, 9, 11, 13, 16, 18, 20,
22, 24, 27, 29, 31, 33, 35, 37, 40, 42,
44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
64, 66, 68, 70, 72, 73, 75, 77, 79, 81,
82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
98, 99, 101, 102, 104, 105, 106, 107, 109, 110,
111, 112, 113, 114, 115, 116, 117, 118, 119, 119,
120, 121, 122, 122, 123, 124, 124, 125, 125, 126,
126, 126, 127, 127, 127, 128, 128, 128, 128, 128,
128,
};
/* sin(угол°) × 128, угол приводится к 0..359. */
int _bgi_sin128(int deg)
{
deg %= 360;
if (deg < 0) deg += 360;
if (deg <= 90) return _bgi_sintab[deg];
if (deg <= 180) return _bgi_sintab[180 - deg];
if (deg <= 270) return -_bgi_sintab[deg - 180];
return -_bgi_sintab[360 - deg];
}
/* cos(угол°) × 128 = sin(угол+90). */
int _bgi_cos128(int deg)
{
return _bgi_sin128(deg + 90);
}
+7
View File
@@ -0,0 +1,7 @@
/* arc — дуга окружности радиуса r от stangle до endangle (градусы). */
#include "_bgi.h"
void arc(int x, int y, int stangle, int endangle, int radius)
{
_bgi_ellipse_arc(x, y, stangle, endangle, radius, radius, _bgi_fg);
}
+17
View File
@@ -0,0 +1,17 @@
/*
* drawpoly — ломаная по numpoints точкам (массив x0,y0,x1,y1,…),
* текущим цветом. Как в Turbo-C, контур НЕ замыкается автоматически:
* чтобы получить замкнутый полигон, повторите первую точку последней.
*/
#include "_bgi.h"
void drawpoly(int numpoints, const int *polypoints)
{
int i;
if (numpoints < 2) return;
for (i = 0; i < numpoints - 1; i++) {
_bgi_lineseg(polypoints[2 * i], polypoints[2 * i + 1],
polypoints[2 * i + 2], polypoints[2 * i + 3],
_bgi_fg);
}
}
+11
View File
@@ -0,0 +1,11 @@
/*
* ellipse — контур эллипса/эллиптической дуги с полуосями xradius,
* yradius от stangle до endangle. Полный эллипс: stangle=0,endangle=360.
*/
#include "_bgi.h"
void ellipse(int x, int y, int stangle, int endangle,
int xradius, int yradius)
{
_bgi_ellipse_arc(x, y, stangle, endangle, xradius, yradius, _bgi_fg);
}