52636a5d6e
Графика вынесена из libc/ в новую библиотеку libbgi/:
- common/ — mode-agnostic математика и состояние (один исходник,
.rel попадает в оба driver-архива);
- bgi256/ + bgi16/ — mode-specific leaf'ы (raw-плот/чтение/спаны);
- include/ — graphics.h + gfx.h; _bgi.h — внутренний заголовок.
Собираются lib/bgi256.lib (и bgi16.lib в Фазе 2); выбор режима
линковкой через sprinter-cc --gfx 256|16. libc/ теперь без графики.
tests/bgi_img — тест спрайтов getimage/putimage/imagesize (5 операций
COPY/XOR/OR/AND/NOT + XOR-round-trip + self-check imagesize).
Проверен автотестом в MAME.
Примечание: make size-check пока красный (gfx_dbuf/gfx_demo выросли
после реорга) — закрыть по завершении миграции libbgi.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
119 lines
4.3 KiB
C
119 lines
4.3 KiB
C
/*
|
|
* gfx_dbuf — double-buffering demo (BGI, bgi256.lib).
|
|
*
|
|
* Рендерит движущийся прямоугольник, чередуя страницу 0 и 1:
|
|
* - Каждый кадр: рисуем на СКРЫТОЙ странице, затем делаем её видимой.
|
|
* - Видимая страница никогда не пишется → пользователь видит только
|
|
* целые кадры (без артефактов, без мерцания от per-frame clear).
|
|
*
|
|
* Переключение страниц и vsync — через mode-agnostic gfx_* (gfx.h,
|
|
* остались в BGI_GFX): gfx_set_draw_page / gfx_set_visible_page /
|
|
* gfx_get_visible_page / gfx_wait_vsync. Рисование — через BGI
|
|
* (graphics.h): cleardevice / bar / rectangle / outtextxy. Режим
|
|
* 0x81 выбирается линковкой: EXTRA_FLAGS=--gfx 256.
|
|
*
|
|
* Индикатор страницы (маленький swatch сверху-справа) меняет оттенок
|
|
* каждый кадр — если бокс движется плавно, а swatch мигает между двумя
|
|
* оттенками, своп работает. Press any key to exit.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <conio.h>
|
|
#include <graphics.h>
|
|
#include <gfx.h> /* double-buffering + vsync (mode-agnostic) */
|
|
#include <stdint.h>
|
|
|
|
static uint8_t palette[256 * 4];
|
|
|
|
#define COL_BLACK 0x00
|
|
#define COL_BG 0x20
|
|
#define COL_STRIPE 0x60
|
|
#define COL_TEXT 0xC0
|
|
#define COL_BOX 0xFF
|
|
#define COL_PAGE0 0x40
|
|
#define COL_PAGE1 0xE0
|
|
|
|
static void make_palette(void)
|
|
{
|
|
for (int i = 0; i < 256; i++) {
|
|
palette[i*4+0] = (uint8_t)i;
|
|
palette[i*4+1] = (uint8_t)i;
|
|
palette[i*4+2] = (uint8_t)i;
|
|
palette[i*4+3] = 0;
|
|
}
|
|
}
|
|
|
|
static void draw_frame(int box_x, int box_y, uint8_t page_indicator)
|
|
{
|
|
setbkcolor(COL_BG); cleardevice();
|
|
|
|
/* Static decoration — identical on both pages so the swap doesn't
|
|
* flicker the chrome. */
|
|
setfillstyle(SOLID_FILL, COL_STRIPE);
|
|
bar(0, 0, GFX_WIDTH - 1, 7);
|
|
bar(0, GFX_HEIGHT - 8, GFX_WIDTH - 1, GFX_HEIGHT - 1);
|
|
|
|
setcolor(COL_TEXT);
|
|
outtextxy(8, 16, "double-buffering demo");
|
|
outtextxy(8, GFX_HEIGHT - 24, "press a key to exit");
|
|
|
|
/* Page indicator — different shade per page: flicker here proves
|
|
* the swap is happening. */
|
|
setfillstyle(SOLID_FILL, page_indicator ? COL_PAGE1 : COL_PAGE0);
|
|
bar(GFX_WIDTH - 24, 16, GFX_WIDTH - 24 + 11, 16 + 11);
|
|
|
|
/* The animated box. */
|
|
setfillstyle(SOLID_FILL, COL_BOX);
|
|
bar(box_x, box_y, box_x + 39, box_y + 29);
|
|
setcolor(COL_BLACK);
|
|
rectangle(box_x, box_y, box_x + 39, box_y + 29);
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
make_palette();
|
|
initgraph();
|
|
|
|
/* Каждая графическая страница имеет свою палитру (0→pal 0, 1→pal 1).
|
|
* Грузим одну и ту же в обе — визуальный своп бесшовный. */
|
|
gfx_pal_load(0, 0, 0, palette);
|
|
gfx_pal_load(1, 0, 0, palette);
|
|
|
|
/* Очистить обе страницы, чтобы первый флип не вскрыл мусор. */
|
|
setbkcolor(COL_BG);
|
|
gfx_set_draw_page(0); cleardevice();
|
|
gfx_set_draw_page(1); cleardevice();
|
|
|
|
/* Bouncing rect state. */
|
|
int box_x = 10;
|
|
int box_y = 100;
|
|
int dx = 3;
|
|
int dy = 2;
|
|
const int box_w = 40, box_h = 30;
|
|
|
|
while (!kbhit()) {
|
|
uint8_t hidden = 1 - gfx_get_visible_page();
|
|
gfx_set_draw_page(hidden);
|
|
|
|
draw_frame(box_x, box_y, hidden);
|
|
|
|
/* Ждать следующий кадр перед флипом — своп падает в vblank,
|
|
* пользователь не видит полунарисованный кадр. */
|
|
gfx_wait_vsync();
|
|
gfx_set_visible_page(hidden);
|
|
|
|
/* Step the box; bounce off all four walls. */
|
|
box_x += dx;
|
|
if (box_x < 0) { box_x = 0; dx = -dx; }
|
|
if (box_x + box_w > GFX_WIDTH) { box_x = GFX_WIDTH - box_w; dx = -dx; }
|
|
box_y += dy;
|
|
if (box_y < 8) { box_y = 8; dy = -dy; }
|
|
if (box_y + box_h > GFX_HEIGHT-8) { box_y = GFX_HEIGHT-8 - box_h; dy = -dy; }
|
|
}
|
|
|
|
(void)getch();
|
|
closegraph();
|
|
puts("done");
|
|
return 0;
|
|
}
|