pascal/bgi/demo_bgi.pas · 9839 字节 · 下载原文
(* demo_bgi.pas —— Pascal 第三层:**传统图形接口**(BGI)
demo_bgi.pas -- Pascal layer 3: the classic graphics interface (BGI)
这一层用的是 Borland 的 `Graph` 单元(BGI = Borland Graphics Interface):
This layer uses Borland's Graph unit (BGI = Borland Graphics Interface):
`InitGraph` / `SetColor` / `Line` / `Rectangle` / `Circle` / `OutTextXY` …
InitGraph / SetColor / Line / Rectangle / Circle / OutTextXY ...
特征是**固定分辨率 + 索引色** —— `SetColor(Red)` 里的 `Red` 是 **4 号调色板索引**,
It is characterised by fixed resolution + indexed colour -- the Red in SetColor(Red) is palette index 4,
不是 RGB 0x000004。
not RGB 0x000004.
整条链是:
The whole chain is:
Pascal 程序
│ uses Graph → CALL InitGraph / GetMaxX / …
▼
Lib/pascal/graph.pas ← **声明**(interface 里有什么名字、什么形状)
Lib/pascal/graph.pas <- the declarations (which names and shapes the interface has)
│ uses graph → AutoLinkUnit 链上 bgi.vml
uses graph -> AutoLinkUnit pulls in bgi.vml
▼
Lib/shared/bgi.vml ← 转发层
Lib/shared/bgi.vml <- forwarding layer
▼
Lib/c/graphics.h ← **唯一的实现**(45 个函数、走宿主 ui_* 图元)
Lib/c/graphics.h <- the single implementation (45 functions, built on host ui_* primitives)
所以在 Pascal 里写 BGI 程序**不用写任何外部声明**(与同目录的 `catch.pas` 同一约定:
So a BGI program in Pascal needs no external declarations at all (same convention as catch.pas beside it:
`uses Graph` 之后裸调即可),实现只有一份,不会出现"同一个程序 C 画得对、
after uses Graph just call them directly); there is only one implementation, so you never get "the same program right in C
Pascal 画得不对"。
but wrong in Pascal".
跑法(桌面 vmlcli —— BGI 垫层开的是**电脑屏窗口**,坐标系固定 640x480 永不重排):
How to run (desktop vmlcli -- the BGI shim opens a computer-screen window, coordinates fixed at 640x480, never relaid out):
dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll Examples/pascal/demo_bgi.pas \
--screen 640x480 --frames out_frames/
⚠ 用 `--frames 目录` 而不是 `--frame 单文件`:本程序结尾调了 `CloseGraph`,
WARNING: use --frames DIR and not --frame SINGLE-FILE: this program calls CloseGraph at the end,
而关窗会把整个场景置空(`VmlHostRuntime.WinClose` 的 `_scene = null`),
and closing the window clears the whole scene (VmlHostRuntime.WinClose sets _scene = null),
跑完之后 `--frame` 已经没有场景可取。`--frames` 是每帧 present 当场拍快照,照常出图。
so afterwards there is no scene left for --frame. --frames snapshots on each present, so images still come out.
画面(从上到下,能一眼看出对错):
The picture (top to bottom, easy to check at a glance):
① 白底(`SetBkColor(White)` + `ClearDevice`)
1) white background (SetBkColor(White) + ClearDevice)
② 一行 16 个色块 —— 0-15 号调色板索引各一条实心竖条(`Bar`)
2) one row of 16 colour blocks -- one solid vertical bar (Bar) per palette index 0-15
③ 左边绿色空心矩形(`Rectangle`)、右边品红实心矩形(`Bar`)
3) a green hollow rectangle (Rectangle) on the left, a magenta solid one (Bar) on the right
④ 中间一个黄圆(`Circle`)+ `FloodFill` 灌成青色
4) a yellow circle (Circle) in the middle, flood-filled with cyan (FloodFill)
⑤ 左下角一条逐点画的对角线(`PutPixel`,看得到"点"的颗粒感)
5) a diagonal drawn point by point (PutPixel) at the lower left, with visible dot grain
⑥ 右上角一个实心椭圆(`FillEllipse`)
6) a solid ellipse (FillEllipse) at the upper right
⑦ 一行 `OutTextXY` 写的文字
7) one line of text drawn with OutTextXY
◆ 两条用法事实
* Two usage facts
· `driver` / `mode` 是**入参+出参**:老程序的标准开场是
. driver / mode are in-out parameters: the classic opening of old programs is
gd := Detect; InitGraph(gd, gm, '');
`gm` 由库回填。`Detect` / `VGA` / `Red` 这些常量都由 `graph.pas` 登记。
gm is filled in by the library. Constants like Detect / VGA / Red are all registered by graph.pas.
· ⚠ **常量以 `Lib/c/graphics.h` 为准,别照 Turbo Pascal 手册抄驱动号** ——
. WARNING: take the constants from Lib/c/graphics.h; do not copy driver numbers from the Turbo Pascal manual --
Borland 的 `CGA=1 / EGA=3`,本垫层按自己的编号(`CGA=3` / `EGA=5`)
Borland has CGA=1 / EGA=3, this shim uses its own numbering (CGA=3 / EGA=5)
在 `_bgi_mode_size` 里查分辨率。老程序实际只用 `Detect` 和 `VGA`,这两个两边一致。
and looks up the resolution in _bgi_mode_size. Old programs really only use Detect and VGA, which agree on both sides.
*)
program DemoBgi;
{ `ui_*`(窗口 / 图元 / 文本 / 帧呈现)声明在 `Lib/pascal/vml_ui.pas`。
The ui_* host UI library (window / primitives / text / present) is declared in
⚠ 必需与否要看写法:**裸写零参**(`ui_2d_present;`)删掉即报「未声明的变量」;
Lib/pascal/vml_ui.pas. WARNING: for a *bare* zero-arg call (`ui_2d_present;`) deleting it
带括号的调用(`ui_2d_present()`)是文档级 —— 但全仓统一写上,**一致性本身就是价值**。
reports an undeclared variable; a parenthesised call is documentation-level. We still
write the reference everywhere for consistency. }
uses
Graph, vml_ui;
var
gd, gm: integer;
i: integer;
begin
{ ── 开场:老程序的标准写法(gd 是入参+出参,gm 由库回填)────────── }
{ -- opening: the standard old-program form (gd is in-out, gm is filled in by the library) ---------- }
gd := Detect;
InitGraph(gd, gm, '');
{ ── ① 白底清屏 ─────────────────────────────────────────────── }
{ -- 1) clear to a white background ------------------------------------------ }
SetBkColor(White);
ClearDevice;
{ ── ② 16 个调色板色块(Bar = 实心矩形)────────────────────── }
{ -- 2) 16 palette colour blocks (Bar = solid rectangle) --------------------- }
for i := 0 to 15 do
begin
SetFillStyle(SolidFill, i);
Bar(20 + i * 38, 20, 20 + i * 38 + 24, 60);
end;
{ ── ③ 空心矩形(Rectangle)与实心矩形(Bar)────────────────── }
{ -- 3) hollow rectangle (Rectangle) and solid rectangle (Bar) ---------------- }
SetColor(Green);
Rectangle(40, 100, 220, 220);
SetFillStyle(SolidFill, Magenta);
Bar(260, 100, 440, 220);
{ ── ④ 圆 + 灌色(Circle + FloodFill)──────────────────────── }
{ -- 4) circle + flood fill (Circle + FloodFill) ----------------------------- }
SetColor(Yellow);
Circle(540, 160, 70);
FloodFill(540, 160, Yellow);
{ ── ⑤ PutPixel 逐点画一条对角线 ─────────────────────────────── }
{ -- 5) draw a diagonal point by point with PutPixel ------------------------ }
for i := 0 to 200 do
PutPixel(60 + i, 260 + i, LightRed);
{ ── ⑥ 实心椭圆(FillEllipse)───────────────────────────────── }
{ -- 6) solid ellipse (FillEllipse) ----------------------------------------- }
SetFillStyle(SolidFill, Cyan);
FillEllipse(500, 340, 80, 50);
{ ── ⑦ 写字(BGI 的文字接口)───────────────────────────────── }
{ -- 7) draw text (the BGI text interface) ---------------------------------- }
SetColor(Blue);
SetTextStyle(DefaultFont, HorizDir, 2);
OutTextXY(30, 400, 'BGI demo in Pascal: SCREEN 640x480, 16 palette colors');
OutTextXY(30, 440, 'InitGraph / Line / Rectangle / Circle / FloodFill / PutPixel');
{ ── 收尾 ①:帧边界。BGI 这一层**自己不画帧边界**(老程序没有帧的概念),
wrap-up 1: frame boundary. The BGI layer does not draw a frame boundary itself (old programs have no frames),
但宿主那套 `ui_*` 是按帧渲染的 ⇒ 末尾补一次 `ui_2d_present()` 告诉宿主
but the host ui_* set renders per frame => add one ui_2d_present() at the end to tell the host
"这一帧画完了"。同目录的 `Examples/c/test_bgi.c` 也是这么收尾的。
"this frame is done". Examples/c/test_bgi.c wraps up the same way.
⚠ 顺序不能反:`ui_2d_present` 必须在 `CloseGraph` **之前** —— 关窗会把整个
WARNING: order matters: ui_2d_present must come before CloseGraph -- closing the window clears the
场景置空,之后再 present 就没有东西可拍了(桌面 `--frames` 会一帧都导不出)。
whole scene, and a later present has nothing to capture (desktop --frames would export no frame at all). }
ui_2d_present();
{ ── 收尾 ②:BGI 的收场白(关窗)─────────────────────────── }
{ -- wrap-up 2: the BGI closing (close the window) ------------------------- }
CloseGraph;
end.