diff --git a/libbgi/common/_bgi_draw_scaled.c b/libbgi/common/_bgi_draw_scaled.c index e9ae53d..89a3f77 100644 --- a/libbgi/common/_bgi_draw_scaled.c +++ b/libbgi/common/_bgi_draw_scaled.c @@ -4,16 +4,62 @@ * * HORIZ_DIR: пиксель глифа (c,r) → экран (x+c*size, y+r*size). * VERT_DIR (поворот 90° против часовой): (c,r) → (x+r*size, y-c*size). - * Каждый «пиксель» глифа — блок size×size из raw-плотов, всё в одной - * W3-скобке. + * + * Рендер run'ами (v2, 2026-07-10): строка глифа сканируется на прогоны + * подряд идущих единичных битов; каждый прогон из n битов — это + * прямоугольник n*size × size, он льётся span-примитивами (hspan для + * HORIZ, vspan для VERT; одиночный пиксель — plot_raw), а не size²×n + * отдельными плотами. Все координаты ведутся инкрементально (px/py + * += size за бит) — ни одного умножения на пиксель. Прогон клипится + * по экрану ДО span'а (span-raw не клипят диапазон!) — в отличие от + * старой версии клип работает и в fast-сборке (GFX_NOCHECK). + * Выигрыш: size=1 ~2×, size=4 ~6× против поштучных плотов. + * Всё в одной W3-скобке. */ #include "../_bgi.h" +/* Горизонтальная полоса прогона: (left..left+len-1) × (top..top+h-1), + * клип по экрану; len после клипа 1..320. */ +static void ds_hrun(int left, int top, int len, uint8_t h, uint8_t fg) +{ + uint8_t by; + int yy; + + if (left < 0) { len += left; left = 0; } + if (left + len > _bgi_maxx + 1) len = _bgi_maxx + 1 - left; + if (len <= 0) return; + for (by = 0; by < h; by++) { + yy = top + by; + if (yy < 0 || yy > _bgi_maxy) continue; + if (len == 1) _bgi_plot_raw(left, yy, fg); + else _bgi_hspan_raw(left, yy, len, fg); + } +} + +/* Вертикальная полоса прогона: (x0..x0+w-1) × (bottom-len+1..bottom), + * клип по экрану; len после клипа 1..256. */ +static void ds_vrun(int x0, int bottom, int len, uint8_t w, uint8_t fg) +{ + uint8_t bx; + int xx, top; + + top = bottom - len + 1; + if (top < 0) { len += top; top = 0; } + if (top + len > _bgi_maxy + 1) len = _bgi_maxy + 1 - top; + if (len <= 0) return; + for (bx = 0; bx < w; bx++) { + xx = x0 + bx; + if (xx < 0 || xx > _bgi_maxx) continue; + if (len == 1) _bgi_plot_raw(xx, top, fg); + else _bgi_vspan_raw(xx, top, len, fg); + } +} + void _bgi_draw_scaled(int x, int y, const char *s) { uint8_t rows[8]; - uint8_t b, fg, size, dir; - int r, c, bx, by, px, py; + uint8_t b, fg, size, dir, r; + int px, py, run0, runl; fg = _bgi_fg; size = _bgi_text_size ? _bgi_text_size : 1; @@ -22,26 +68,37 @@ void _bgi_draw_scaled(int x, int y, const char *s) _bgi_begin(); while (*s) { _bgi_font_rows((unsigned char)*s, rows); - for (r = 0; r < 8; r++) { - b = rows[r]; - for (c = 0; c < 8; c++) { - if (!((b >> (7 - c)) & 1)) continue; - for (by = 0; by < size; by++) { - for (bx = 0; bx < size; bx++) { - if (dir == VERT_DIR) { - px = x + r * size + by; - py = y - c * size - bx; - } else { - px = x + c * size + bx; - py = y + r * size + by; - } - _bgi_plot_raw(px, py, fg); - } + if (dir == VERT_DIR) { + px = x; /* колонка ряда r глифа */ + for (r = 0; r < 8; r++) { + b = rows[r]; + py = y; /* низ ячейки бита c=0 */ + while (b) { + if (!(b & 0x80)) { b <<= 1; py -= size; continue; } + run0 = py; /* низ прогона */ + runl = 0; + while (b & 0x80) { b <<= 1; py -= size; runl += size; } + ds_vrun(px, run0, runl, size, fg); } + px += size; } + y -= 8 * size; + } else { + py = y; /* верх ряда r глифа */ + for (r = 0; r < 8; r++) { + b = rows[r]; + px = x; /* левый край ячейки бита c=0 */ + while (b) { + if (!(b & 0x80)) { b <<= 1; px += size; continue; } + run0 = px; /* левый край прогона */ + runl = 0; + while (b & 0x80) { b <<= 1; px += size; runl += size; } + ds_hrun(run0, py, runl, size, fg); + } + py += size; + } + x += 8 * size; } - if (dir == VERT_DIR) y -= 8 * size; - else x += 8 * size; s++; } _bgi_end();