c/bgi/demo_bgi.c · 12594 字节 · 下载原文
/* demo_bgi.c —— **第 3 层:传统图形接口**(BGI / Borland Graphics Interface)
* demo_bgi.c -- **Layer 3: the classic graphics interface** (BGI / Borland Graphics Interface)
*
* 这一层与下面第 4 层(`ui_*`)的差别,是**两个年代的两套假设**:
* What separates this layer from layer 4 (`ui_*`) below is two eras' two sets of assumptions:
*
* · **固定分辨率**:程序开一个 `SCREEN 12` / `VGAHI` 就不再管屏幕大小了,
* · **Fixed resolution**: once a program opens `SCREEN 12` / `VGAHI` it stops caring about screen size,
* 代码里到处是 `640`、`480` 这种写死的坐标。宿主负责把这块固定画布
* and the code is full of hard-coded coordinates like `640`, `480`. The host places that fixed canvas
* 摆到真实屏幕上(本平台走的是 `ui_win_open_pc`,坐标系**不随旋转重排**)。
* onto the real screen (here through `ui_win_open_pc`, whose coordinate system is **not re-laid-out on rotation**).
* · **索引色**:`setcolor(4)` 说的是「红」,不是 RGB `0x000004`。
* · **Indexed color**: `setcolor(4)` means "red", not the RGB value `0x000004`.
* 全套只有 16 个颜色号,老程序里 `RED`/`LIGHTGREEN`/`YELLOW` 这些名字满天飞。
* There are only 16 color numbers in all, and old programs are full of names like `RED`/`LIGHTGREEN`/`YELLOW`.
*
* `Lib/c/graphics.h` 把 BGI 的**函数名与语义**原样接过来,落笔换成平台的 `ui_*`。
* `Lib/c/graphics.h` takes over BGI's **function names and semantics** as-is and swaps drawing to the platform's `ui_*`.
* 所以这个 demo 就是一份**标准的老式图形程序**:开场 `initgraph`、画、`closegraph`。
* So this demo is a **standard old-style graphics program**: open with `initgraph`, draw, `closegraph`.
*
* ## 覆盖了什么
* ## What is covered
*
* `initgraph(DETECT)` 取到 VGA 640×480 → 铺底 → 16 色色带 →
* `initgraph(DETECT)` yields VGA 640x480 -> fill the background -> a 16-color bar ->
* 直线 / 折线 / 矩形 / 实心条 / 外框条 / 圆 / 实心椭圆 / 弧 / 扇形 / 多边形 →
* lines / polylines / rectangles / filled bars / 3D bars / circles / filled ellipses / arcs / pies / polygons ->
* 三档字号 + 三种对齐的文字 → `closegraph`。
* three text sizes + three text alignments -> `closegraph`.
*
* ⚠ 本 demo **不调 `getch()`**(老程序常见的收尾)。`conio` 的 `getch()` 在本平台是
* WARNING: this demo does **not** call `getch()` (the usual ending of old programs). Here `conio`'s `getch()` is
* "按行"取的(用户在输入框敲一行再提交),图形窗口里按不了键 —— 调它会把程序
* read "by line" (the user types a line into the input box and submits it), and the graphics window cannot take keys --
* 挂在那儿等一个永远不来的输入。所以画完直接 `closegraph()` 正常结束。
* calling it would hang the program waiting for input that never arrives. So after drawing we call `closegraph()` and end normally.
* 要交互请看 `demo_ui.c`(那一层有真正的消息循环)。
* For interaction see `demo_ui.c` (that layer has a real message loop).
*
* 跑法:命令行页输入 vml run examples/c/demo_bgi.c
* Run: type in the command-line page vml run examples/c/demo_bgi.c
* 桌面出图:vmlcli Examples/c/demo_bgi.c --frame out.png
* Desktop rendering: vmlcli Examples/c/demo_bgi.c --frame out.png
*/
#include <vml_ui.h>
#include <graphics.h>
#define VBAR_X 40 /* 调色板色带的起点
* start x of the palette color bar */
#define VBAR_Y 92
int main(void)
{
int gd = DETECT;
int gm = 0;
int i;
int x, y;
int tri[8];
int lang = ui_scr_get_language(); /* 界面语言:开局查一次(ui_scr_get_language 是 syscall,别每帧调) */
/* UI language: queried once at start (ui_scr_get_language is a syscall, do not call it every frame) */
/* ── 1. 开场:老程序的标准三行 ──
* -- 1. Intro: the standard three lines of an old graphics program --
* `DETECT` 让库自己挑驱动/模式;本平台挑出来是 VGA + VGAHI(640×480)。
* `DETECT` lets the library pick the driver/mode; here it picks VGA + VGAHI (640x480). */
initgraph(&gd, &gm, "");
/* ── 2. 铺底:背景色是索引色,`cleardevice` 整屏刷成它 ──
* -- 2. Background: the background color is an indexed color, and `cleardevice` floods the screen with it -- */
setbkcolor(BLACK);
cleardevice();
/* ── 3. 标题(索引色 14 = 黄,字号 3 = 3×16 像素)──
* -- 3. Title (indexed color 14 = yellow, text size 3 = 3x16 pixels) -- */
setcolor(YELLOW);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 3);
/* ⚠ 竖档必须写 `TOP_TEXT`(**盒顶**落在 y),**不能写 0** —— 0 是 `BOTTOM_TEXT`
* WARNING: the vertical alignment must be `TOP_TEXT` (the **top** of the box lands on y), **never 0** --
* (盒**底**落在 y)。字号 3 的盒高是 48px,写 0 的话整块标题被顶到屏幕外、
* 0 is `BOTTOM_TEXT` (the **bottom** of the box lands on y). At size 3 the box is 48px tall, so writing 0
* 只剩底部十来行可见(`outtextxy` 的 y 是**盒顶**,这是 BGI 的缺省对齐)。
* pushes the whole title off the screen with only the bottom ten-odd rows visible (`outtextxy`'s y is the
* **top** of the box; that is BGI's default alignment). */
settextjustify(CENTER_TEXT, TOP_TEXT);
outtextxy(getmaxx() / 2, 12, lang == 0 ? "BGI 传统图形接口 / demo_bgi.c" : "BGI classic graphics / demo_bgi.c");
settextstyle(DEFAULT_FONT, HORIZ_DIR, 1);
/* `0` = `BOTTOM_TEXT`:正文行按"盒底贴着 y"排。
* `0` = `BOTTOM_TEXT`: body lines are laid out with the box bottom against y.
* ⚠ **别改成 `TOP_TEXT`** —— 那会把下面每一行整体再下移约 0.8×字号(16px 字号 ≈ 13px),
* WARNING: **do not change it to `TOP_TEXT`** -- that shifts every line below down by about 0.8x the font size
* 底部的 `putpixel / getcolor` 会被顶出画布。
* (16px font is about 13px) and pushes `putpixel / getcolor` at the bottom off the canvas. */
settextjustify(LEFT_TEXT, 0);
/* 一行说明:屏幕尺寸是**开窗时定死的**,程序照着它排的版。
* One line of explanation: the screen size is **fixed when the window opens**, and the program lays out for it.
* y 取 74(不是 62):上面那行标题按 TOP 排时盒子占到 y=60,得给它让出位置。
* y is 74 (not 62): the title line above occupies up to y=60 when laid out with TOP, so it needs the room. */
setcolor(LIGHTGRAY);
outtextxy(20, 74, "fixed resolution 640x480, 16-color indexed palette (setcolor(0..15))");
/* ── 4. 16 色色带 —— 这一层「索引色」最直观的一张图 ──
* -- 4. The 16-color bar -- the most direct picture of this layer's "indexed color" --
* 每一格用 `setfillstyle(SOLID_FILL, i)` + `bar()`,色号就是 BGI 的索引。
* Each cell uses `setfillstyle(SOLID_FILL, i)` + `bar()`; the color number is the BGI index. */
for (i = 0; i < 16; i++) {
setfillstyle(SOLID_FILL, i);
bar(VBAR_X + i * 34, VBAR_Y, VBAR_X + i * 34 + 30, VBAR_Y + 34);
}
setcolor(WHITE);
rectangle(VBAR_X - 1, VBAR_Y - 1, VBAR_X + 16 * 34 + 1, VBAR_Y + 35);
setcolor(LIGHTGRAY);
outtextxy(VBAR_X, VBAR_Y + 50, "0 black 1 blue 2 green 3 cyan 4 red 5 magenta 6 brown 7 lightgray");
outtextxy(VBAR_X, VBAR_Y + 66, "8 darkgray 9 lightblue 10 lightgreen 11 lightcyan 12 lightred 13 lightmagenta 14 yellow 15 white");
/* ── 5. 直线与折线(`moveto` + `lineto` / `linerel` 是老程序画的常规姿势)──
* -- 5. Lines and polylines (`moveto` + `lineto` / `linerel` is how old programs usually draw) -- */
setcolor(LIGHTGREEN);
line(40, 210, 200, 210);
moveto(40, 230);
lineto(120, 230);
linerel(80, 0);
setcolor(LIGHTCYAN);
moveto(40, 250);
linerel(40, -20);
linerel(40, 20);
linerel(40, -20);
linerel(40, 20);
setcolor(LIGHTGRAY);
outtextxy(40, 262, lang == 0 ? "line / moveto / lineto / linerel (折线开口)"
: "line / moveto / lineto / linerel (open polyline)");
/* ── 6. 矩形与两种"条"(`bar` 实心 / `bar3d` 立体)──
* -- 6. Rectangles and two kinds of bar (`bar` solid / `bar3d` with depth) -- */
setcolor(YELLOW);
rectangle(250, 205, 370, 265);
setfillstyle(SOLID_FILL, LIGHTBLUE);
bar(380, 205, 450, 265);
setfillstyle(SOLID_FILL, GREEN);
setcolor(WHITE);
bar3d(465, 215, 545, 265, 14, 1);
setcolor(LIGHTGRAY);
outtextxy(250, 272, "rectangle / bar / bar3d");
/* ── 7. 圆与椭圆(索引色描边、`setfillstyle` 填充)──
* -- 7. Circles and ellipses (stroked with indexed colors, filled by `setfillstyle`) -- */
setcolor(LIGHTMAGENTA);
circle(80, 330, 40);
circle(80, 330, 24);
setfillstyle(SOLID_FILL, BROWN);
fillellipse(200, 330, 56, 34);
setcolor(LIGHTGRAY);
ellipse(200, 330, 0, 360, 70, 44);
outtextxy(40, 388, "circle / fillellipse / ellipse");
/* ── 8. 弧与扇形(这两样只有"刷子接口"画得了,见 graphics.h 的说明)──
* -- 8. Arcs and pies (only the "brush interface" can draw these two; see the notes in graphics.h) -- */
setcolor(LIGHTRED);
arc(330, 330, 30, 150, 40);
setcolor(WHITE);
setfillstyle(SOLID_FILL, YELLOW);
pieslice(420, 330, 200, 340, 40);
setcolor(LIGHTGRAY);
outtextxy(290, 388, lang == 0 ? "arc (描边) / pieslice (填充)"
: "arc (stroke) / pieslice (fill)");
/* ── 9. 多边形(⚠ BGI 的顶点表**首点要重复一次**才闭合,这是老规矩)──
* -- 9. Polygons (WARNING: a BGI vertex list must **repeat the first point** to close; that is the old rule) -- */
tri[0] = 520; tri[1] = 370;
tri[2] = 560; tri[3] = 300;
tri[4] = 600; tri[5] = 370;
tri[6] = tri[0]; tri[7] = tri[1];
setcolor(LIGHTGREEN);
drawpoly(4, tri);
setfillstyle(SOLID_FILL, LIGHTMAGENTA);
setcolor(WHITE);
fillpoly(4, tri);
setcolor(LIGHTGRAY);
outtextxy(520, 388, "drawpoly / fillpoly");
/* ── 10. 像素与读回(老程序靠它做"这个点是什么颜色"的判断)──
* -- 10. Pixels and read-back (how old programs ask "what color is this point") -- */
for (y = 0; y < 6; y++) {
for (x = 0; x < 16; x++) {
/* 棋盘格:两种索引色交替,肉眼一看就知道 putpixel 生效了
* A checkerboard: two indexed colors alternate, so one glance shows putpixel took effect */
setcolor((x + y) % 2 == 0 ? WHITE : BLUE);
putpixel(60 + x * 8, 410 + y * 8, getcolor());
}
}
setcolor(LIGHTGRAY);
outtextxy(40, 466, "putpixel / getcolor");
/* ── 11. 三档字号 + 三种对齐(老程序居中排版就靠 settextjustify)──
* -- 11. Three text sizes + three alignments (old programs center text with settextjustify) -- */
setcolor(WHITE);
settextstyle(DEFAULT_FONT, HORIZ_DIR, 2);
settextjustify(LEFT_TEXT, 0);
outtextxy(300, 405, "LEFT");
settextjustify(CENTER_TEXT, 0);
outtextxy(430, 405, "CENTER");
settextjustify(RIGHT_TEXT, 0);
outtextxy(620, 405, "RIGHT");
settextstyle(DEFAULT_FONT, HORIZ_DIR, 1);
settextjustify(LEFT_TEXT, 0);
outtextxy(300, 430, "settextstyle(size) + settextjustify(LEFT/CENTER/RIGHT)");
/* ── 12. 收尾 ──
* -- 12. Wrap-up --
* `closegraph` 关掉窗口。**不调 `getch()`**,理由见文件头。
* `closegraph` closes the window. **No `getch()` call**; see the file header for why.
*
* 出图靠宿主:桌面是 `--frame out.png`,手机上是窗口自己贴。
* The host does the rendering: `--frame out.png` on desktop, and the window blits itself on mobile. */
ui_2d_present();
closegraph();
return 0;
}