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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user