本程式在 Turbo C 2.0 環境下開發,提供一個互動式繪圖環境:
| 按鍵 | 功能 | 畫筆圖示 |
|---|---|---|
| V | 提起畫筆(移動不留痕) | □ |
| W | 落下畫筆(移動繪製線條) | ■ |
| R | 擦除模式(移動清除像素) | ◆ |
| C | 以當前位置為圓心畫半徑 20 像素的圓 | — |
| S | 將當前畫面存入 pic.dat | — |
| E | 從 pic.dat 讀取畫面繼續編輯 | — |
#include <graphics.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
void save(char*), load(char*);
void *wg, *rg, *vg, *fy; // 畫筆圖示緩衝區
int driver, mode;
int c = RED;
int x = 320, y = 225; // 畫筆初始座標
int x1, y1, x2, y2;
int k, k1, k2;
void main() {
/* 初始化繪圖系統 */
detectgraph(&driver, &mode);
initgraph(&driver, &mode, "c:\\tc");
/* 繪製三種畫筆圖示:提起、繪圖、擦除 */
bar(200,10,206,16); // 提起:方框
line(203,7,200,10); line(203,7,206,10);
line(243,7,240,16); line(243,7,246,16); // 繪圖:筆尖
line(283,7,280,10); line(283,7,286,10); line(283,7,283,16); // 擦除:橡皮擦
/* 將圖示存入記憶體緩衝區 */
wg = malloc(imagesize(200,7,206,16));
rg = malloc(imagesize(240,7,246,16));
vg = malloc(imagesize(280,7,286,16));
fy = malloc(imagesize(200,7,206,16));
getimage(200,7,206,16,wg);
getimage(240,7,246,16,rg);
getimage(280,7,286,16,vg);
cleardevice();
/* 繪製黃色繪圖邊框 */
setcolor(YELLOW);
rectangle(4,19,637,447);
/* 畫筆初始顯示(提起狀態) */
x1 = x-3; y1 = y+1; x2 = x+3; y2 = y+10;
getimage(x1,y1,x2,y2,fy); // 備份畫筆下方背景
putimage(x1,y1,vg,XOR_PUT); // XOR 顯示提起圖示
/* 主事件迴圈 */
for (;;) {
while (bioskey(1) == 0); // 等待按鍵
k = bioskey(0); // 讀取鍵碼
putimage(x1,y1,fy,AND_PUT); // 恢復背景(清除舊畫筆)
if (((k & 0x00ff) | 0x00) == 0) { // 功能鍵(掃描碼在高位元組)
k1 = k & 0xff ? 0 : k >> 8;
} else { // 一般字元鍵
k2 = k & 0x00ff;
}
/* 功能鍵處理:方向移動 */
if (((k & 0x00ff) | 0x00) == 0) {
switch(k1) {
case 45: restorecrtmode(); exit(0); // X 鍵退出
case 72: if (y > 20) y--; break; // 上
case 75: if (x > 5) x--; break; // 左
case 77: if (x < 636) x++; break; // 右
case 80: if (y < 446) y++; break; // 下
case 71: if (x > 5 && y > 20) { x--; y--; } break; // 左上
case 79: if (x > 5 && y < 446) { x--; y++; } break; // 左下
case 73: if (x < 636 && y > 20) { x++; y--; } break; // 右上
case 81: if (x < 636 && y < 446) { x++; y++; } break;// 右下
}
}
/* 更新畫筆位置並重繪 */
x1 = x-3; y1 = y+1; x2 = x+3; y2 = y+10;
getimage(x1,y1,x2,y2,fy);
/* 一般字元鍵處理 */
switch(k2) {
case 118: case 86: // V/v - 提起
putimage(x1,y1,vg,OR_PUT); break;
case 119: case 87: // W/w - 繪圖
putimage(x1,y1,wg,OR_PUT); putpixel(x,y,c); break;
case 114: case 82: // R/r - 擦除
putimage(x1,y1,rg,OR_PUT); putpixel(x,y,BLACK); break;
case 115: case 83: // S/s - 存檔
save("pic.dat"); break;
case 101: case 69: // E/e - 讀檔
load("pic.dat"); break;
case 99: case 67: // C/c - 畫圓
setcolor(RED); circle(x,y,20); break;
default: continue;
}
}
/* 存檔:將 VGA 顯示記憶體 4 個平面逐一寫入檔案 */
void save(char *fname) {
FILE *fp = fopen(fname, "wb");
char far *ptr = (char far *)0xA0000000L;
for (int i = 0; i < 4; i++) {
outportb(0x3CE, 4); outportb(0x3CF, i); // 選擇平面
for (register long j = 0; j < 38400L; j++)
putc(*ptr++, fp);
}
fclose(fp);
outportb(0x3CF, 0);
}
/* 讀檔:從檔案還原 4 個平面到顯示記憶體 */
void load(char *fname) {
FILE *fp = fopen(fname, "rb");
char far *ptr = (char far *)0xA0000000L;
int k4 = 1;
for (int i = 0; i < 4; i++) {
outportb(0x3C4, 2); outportb(0x3C5, k4); // 選擇平面
for (register long j = 0; j < 38400L; j++)
*ptr++ = getc(fp);
k4 *= 2;
}
fclose(fp);
outportb(0x3C5, 0xF);
}
程式在 Turbo C 2.0 驗證通過,展示了 DOS 時代直接操作硬體的經典技法。可擴充方向: