cp03.docx
《cp03.docx》由会员分享,可在线阅读,更多相关《cp03.docx(26页珍藏版)》请在冰豆网上搜索。
![cp03.docx](https://file1.bdocx.com/fileroot1/2023-2/21/afd70a30-c3f9-43b4-bbcd-926fe96c4316/afd70a30-c3f9-43b4-bbcd-926fe96c43161.gif)
cp03
0、预备知识
0.1开发平台:
DosBox+WatcomC
①文档下载
②软件下载
假定把上述压缩包解压到D:
\
双击D:
\DosBoxWc\wc.exe进入dosbox
可以看到DosBox中显示的当前文件夹为c:
\watcom\project
请注意此文件夹是虚拟的,实际对应的物理路径为:
D:
\DosBoxWc\watcom\project
0.2如何编辑源程序?
推荐使用第三方编辑器如editplus(下载链接:
),也可以用watcomC自带的vi编辑器。
写好的程序应放在D:
\DosBoxWc\watcom\project内。
0.3如何编译?
WCL386hello.c
0.4如何运行?
hello
若错误信息太多,可以打开hello.err查看。
0.5如何调试?
调试前要对源程序重新编译,编译命令如下:
WCL386/d2hello.c
再输入调试命令:
WD/tr=rsihello
调试按键:
F10stepover执行一步,不跟踪到函数内部
F8traceinto执行一步,跟踪到函数内部
F4userscreen观察程序的输出结果
某行左侧的[]处点击鼠标可以设一个断点
0.6多个.c文件如何整合编译成一个.exe?
先建立1.c,2.c
再建立makefile,其内容如下:
12.exe:
1.c2.c
wcl386/fe=12.exe1.c2.c
最后输入以下命令进行build:
wmake
一、坐标系统及graphics图形库中定义的全局变量
二、文本模式(textmode)编程指南
DosBox刚运行时显卡的工作模式就是文本模式;
要让显卡工作在图形模式的话,必须调用函数initgraph();若要从图形模式返回文本模式,则应该调用函数closegraph()或text_mode()或textmode(C80);
例1:
程序a.c在屏幕(0,0)处输出一个蓝色背景红色前景的字母'A',在屏幕(1,0)处输出一个绿色背景白色前景的字母'B'。
请注意,文本模式下,8位颜色值中的高4位为背景色,低4位为前景色,所以当设定蓝底红字时,颜色值应该等于(BLUE<<4)+RED=(1<<4)+4=0x14。
例2:
程序b.c输出2000个黑色背景红色前景的'A'。
三、图形模式(graphicsmode)编程指南
3.18bit图形模式
1个点对应显存的1个字节,每个点最多有256种颜色变化。
例3:
程序c.c画一条红色水平线。
#include
#include
main()
{
intdriver=0,mode=VESA_1024x768x8bit;
char*p;
intx=100,y=100,i;
initgraph(&driver,&mode,"");
p=_vp+y*_width+x;
for(i=x;i<600-x+1;i++)
{
*p++=RED;//或写成*p++=4;
}
getchar();
}
程序c.c;(100,100)-(600,100)画一条红色水平线
8bit图形模式下的颜色编号与颜色的对应关系(如4对应红色)与文本模式类似,具体请查阅头文件graphics.h中enumCOLORS的定义或主页文档中的相关内容。
例4:
程序256color.c可以把全部256种颜色画出来:
3.224bit图形模式
1个点对应显存的3个字节,每个点的颜色有224种变化。
以下示意图展示了VESA_1024x768x24bit模式下,如何在(0,0)处画了一个红点,在(x,y)处画一个青点:
程序24bit0.c、24bit1.c、24bit2.c、24bit3.c功能完全一样,都以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
但它们实现的过程有所不同。
其中24bit3.c是最简单的,它直接调用bar()函数来画矩形;24bit2.c则是调用putpixel()函数画矩形中的每一个点;24bit1.c是通过语句p[y][x]=c画矩形中的每一个点;24bit0.c是通过语句
*p=(*p&0xFF000000)|color;
画矩形中的每一个点,上述语句的的执行过程可以用如下示意图描述:
例5:
程序24bit0.c使用指针写显存画点,以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
#include
main()
{
intdriver=0,mode=VESA_1024x768x24bit;
intx,y;
longcolor=0x0000FFFF;
long*p;
initgraph(&driver,&mode,"");
for(y=100;y<=300;y++)
{
for(x=200;x<=400;x++)
{
p=(long*)(
_vp+(y*_width+x)*
(_color_bits/8)
);
*p=(*p&0xFF000000)|color;
}
}
getchar();
closegraph();
}
程序24bit0.c
例6:
程序24bit1.c使用二维结构数组写显存画点,以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
#include
typedefstruct
{
charblue;
chargreen;
charred;
}RGB;
main()
{
intdriver=0,mode=VESA_1024x768x24bit;
intx,y;
RGBc={0xFF,0xFF,0x00};
RGB(*p)[1024];
initgraph(&driver,&mode,"");
p=(RGB(*)[1024])_vp;
for(y=100;y<=300;y++)
{
for(x=200;x<=400;x++)
{
p[y][x]=c;//此语句相当于以下三句
//p[y][x].blue=c.blue;
//p[y][x].green=c.green;
//p[y][x].red=c.red;
}
}
getchar();
closegraph();
}
程序24bit1.c
例7:
程序24bit2.c调用函数putpixel()画点,以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
#include
main()
{
intdriver=0,mode=VESA_1024x768x24bit;
intx,y;
longcolor=0x0000FFFF;
initgraph(&driver,&mode,"");
for(y=100;y<=300;y++)
{
for(x=200;x<=400;x++)
{
putpixel(x,y,color);//调用画点函数
}
}
getchar();
closegraph();
}
程序24bit2.c
例8:
程序24bit3.c调用函数bar(),以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
#include
main()
{
intdriver=0,mode=VESA_1024x768x24bit;
longcolor=0x0000FFFF;
initgraph(&driver,&mode,"");
//设定填充的模式及颜色
setfillstyle(SOLID_FILL,color);
bar(200,100,400,300);//调用画实心矩形函数
getchar();
closegraph();
}
程序24bit3.c
3.332bit图形模式
1个点对应显存的4个字节,每个点的颜色有224种变化。
程序32bit.c也是以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
例9:
程序32bit.c在32bit图形模式下使用二维结构数组画点,以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
#include
typedefstruct
{
charblue;
chargreen;
charred;
charzero;
}RGB;
main()
{
intdriver=0,mode=VESA_1024x768x32bit;
intx,y;
RGBc={0xFF,0xFF,0x00,0x00};
RGB(*p)[1024];
initgraph(&driver,&mode,"");
p=(RGB(*)[1024])_vp;
for(y=100;y<=300;y++)
{
for(x=200;x<=400;x++)
{
p[y][x]=c;
}
}
getchar();
closegraph();
}
程序32bit.c
由于例9程序中的RGB结构成员的长度加起来刚好是4字节,因此完全可以用long类型来取代RGB结构,修改后的程序32bitx.c如下所示:
例10:
程序32bitx.c在32bit图形模式下使用二维long型数组画点,以(200,100)为左上角,以(400,300)为右下角画一个实心的青色矩形。
#include
main()
{
intdriver=0,mode=VESA_1024x768x32bit;
intx,y;
longc=0x0000FFFF;
//red=0x00,green=0xFF,blue=0xFF
long(*p)[1024];
initgraph(&driver,&mode,"");
p=(long(*)[1024])_vp;
for(y=100;y<=300;y++)
{
for(x=200;x<=400;x++)
{
p[y][x]=c;
}
}
getchar();
closegraph();
}
程序32bitx.c
四、图片输出
4.1显示8bitbmp图片
调用函数load_8bit_bmp()可以在指定坐标位置显示一张256色bmp图片。
例11:
程序8bitbmp.c调用函数load_8bit_bmp()在坐标(0,0)显示一张图片pic256.bmp,再在坐标(200,200)显示另一张图片hello.bmp。
程序8bitbmp.c及配套图片文件打包下载链接:
#include
#include
main()
{
intx,y;
intdriver=0,mode=VESA_1024x768x8bit;
initgraph(&driver,&mode,"");
load_8bit_bmp(0,0,"pic256.bmp");
load_8bit_bmp(200,200,"hello.bmp");
getchar();
closegraph();
}
程序8bitbmp.c
4.2显示24bitbmp图片
例12:
程序24bitbmp.c先定义了一个用户自定义函数load_24bit_bmp(),再在函数main()中调用此自定义函数于坐标(0,0)处显示一张24bitbmp图片pic.bmp。
程序24bitbmp.c及配套图片文件打包下载链接:
#include
#include
#include
intload_24bit_bmp(intx,inty,char*filename)
{
FILE*fp=NULL;
byte*p=NULL;/*pointertoalineofbmpdata*/
byte*vp=_vp+(y*_width+x)*(_color_bits/8);
dwordwidth,height,bmp_data_offset,bytes_per_line,offset;
inti;
p=malloc(1024L*3);/*memoryforholdingalineofbmpdata*/
if(p==NULL)/*cannotallocateenoughmemoryfordrawing1line*/
gotodisplay_bmp_error;
fp=fopen(filename,"rb");
if(fp==NULL)/*cannotopenbmpfile*/
gotodisplay_bmp_error;
fread(p,1,0x36,fp);/*readBMPhead*/
if(*(word*)p!
=0x4D42)/*checkBMPsignature*/
gotodisplay_bmp_error;/*notaBMPfile*/
if(*(word*)(p+0x1C)!
=24)
gotodisplay_bmp_error;/*nota24-bit-colorBMPfile*/
width=*(dword*)(p+0x12);
height=*(dword*)(p+0x16);
bmp_data_offset=*(dword*)(p+0x0A);
fseek(fp,bmp_data_offset,SEEK_SET);/*skipBMPhead*/
bytes_per_line=(width*3+3)/4*4;/*mustbemultipleof4*/
for(i=height-1;i>=0;i--)/*drawfrombottomtotop*/
{
fread(p,1,bytes_per_line,fp);/*readalineofbmpdata*/
offset=i*1024*3;
memcpy(vp+offset,p,width*3);
}
free(p);
fclose(fp);
return1;
display_bmp_error:
if(p!
=NULL)
free(p);
if(fp!
=NULL)
fclose(fp);
return0;
}
main()
{
intdriver=0,mode=VESA_1024x768x24bit;
initgraph(&driver,&mode,"");
load_24bit_bmp(0,0,"pic.bmp");
getchar();
closegraph();
}
程序24bitbmp.c
五、文字输出
5.1文本模式下的字符输出
文本模式下只能输出英文,不能输出中文。
如果不考虑输出的坐标位置,则可以调用printf()、puts()输出字符串;如果要在指定坐标位置输出字符串,则可以先调用函数gotoxy()把光标定位到指定位置,再调用函数puts()输出字符串。
例13:
程序text1.c调用gotoxy()控制输出坐标,先在坐标(1,1)处输出字符串"Hello,Tom!
",再在坐标(2,2)处输出字符串"Hello,Jerry"。
#include
#include
main()
{
clrscr();//清屏
gotoxy(1,1);
puts("Hello,Tom!
");
gotoxy(2,2);
puts("Hello,Jerry!
");
getchar();
}
程序text1.c
请注意gotoxy()函数中,横坐标及纵坐标都是以1为基的,即(1,1)相当于实际坐标(0,0)。
在文本模式下,除了调用gotoxy(),还可以使用视频指针_vp来控制输出的坐标及内容。
例14:
程序text2.c使用指针vp控制输出坐标及颜色和内容,先在坐标(0,0)处输出黑色背景白色前景的字符串"Hello,Tom!
",再在坐标(1,1)处输出蓝色背景红色前景的字符串"Hello,Jerry"。
#include
#include
voidputsxy(intx,inty,char*s,charcolor)
{
char*vp=_vp+(y*_width+x)*2;
inti=0;
while(s[i]!
='\0')
{
*vp=s[i];
*(vp+1)=color;
vp+=2;
i++;
}
}
main()
{
clrscr();
putsxy(0,0,"Hello,Tom!
",BLACK<<4|WHITE);
putsxy(1,1,"Hello,Jerry!
",BLUE<<4|RED);
getchar();
}
程序text2.c
5.2图形模式下的字符输出
5.2.1图形模式下的英文输出
图形模式下可调用outtextxy()在指定坐标位置输出一个英文字符串。
例15:
程序outtext.c在坐标(100,100)处输出白色字符串"Hello,Tom!
",再在坐标(200,200)处输出红色字符串"Hello,Jerry!
"。
#include
#include
main()
{
intdriver=0,mode=VESA_1024x768x24bit;
initgraph(&driver,&mode,"");
//默认颜色为白色
outtextxy(100,100,"Hello,Tom!
");
setcolor(0xFF0000);//设置颜色为红色
//其中red=0xFF,green=0x00,blue=0x00
//注意图形模式下的颜色不能使用RED、GREEN、BLUE
//等常数,而应该用RGB成份进行定义
outtextxy(200,200,"Hello,Jerry!
");
getchar();
closegraph();
}
程序outtext.c
请注意,outtextxy()输出字符串的颜色是指前景色,该颜色由setcolor()函数指定。
outtextxy()并不描绘字符串的背景,也就是说setbkcolor()函数指定的背景色对outtextxy()无任何影响。
另外,outtextxy()是按8*16点阵输出字符,即字体大小是固定的。
5.2.2图形模式下的中文输出
图形模式下可以自己编程读取汉字的点阵字库描出16*16个点。
例16:
程序hz.c读取点阵字库hzk中"我"字的16*16点阵共32字节信息并在屏幕中间位置画出该字。
程序hz.c及相关的字库文件hzk打包下载链接:
程序hz.c通过画一个4*4的方块来描绘一个点,因此实际上把汉字放大了4倍。
但是,放大以后的汉字呈明显的锯齿形。
为了克服点阵汉字不能放大的缺陷,我们可以使用TTF曲线字库来输出汉字。
其中快速输出可以通过调用函数get_ttf_text_pic()及draw_picture()实现,慢速输出可以通过调用函数out_ttf_text_xy()实现。
例17:
程序ttftest.c演示了TTF字体的快速输出及慢速输出两种方式。
程序ttftest.c及配套字库打包下载链接:
六、声音输出
6.1扬声器输出
例18:
程序music.c演示了如何控制杨声器发声,演奏一首歌。
程序music.c下载链接:
6.2声卡输出
例19:
程序sound.c演示了如何调用函数play_wave()及play_midi()输出wav波形文件及midi音乐文件。
程序sound.c及配套声音文件打包下载链接:
七、输入
7.1键盘输入
charx;
scanf("%c",&x);
x=getchar();
上述两个函数在输入一个字符时需要敲回车表示输入的结束;输入的符号会显示在屏幕上;一些特殊的键无法输入如上下左右方向键。
函数bioskey()可以代替上述函数,并且克服以上3个不足之处。
intkey;
key=bioskey(0);
其中key是一个16位整数。
若当前键盘缓冲区是空的,则执行bioskey(0)会等待用户敲键;若当前键盘缓冲区非空,则执行bioskey(0)会把键盘缓冲区中的键读走,不会等待用户输入。
bioskey
(1)用来检测键盘缓冲区是否为空,若缓冲区为空,则bioskey
(1)返回0,否则返回非零。
什么是键盘缓冲区?
CPU能在运行程序时处理外部中断(interrupt)。
当用户按下某个键时,键盘会向CPU发出一个中断请求,此时CPU会暂停正在运行的程序而转去处理键盘中断,处理的结果是把当前按住的键读走并存放到键盘缓冲区中。
键盘缓冲区是一个队列(queue),相当于一个数组。
例20:
程序blkctrl1.c演示了如何用bioskey(0)控制键移动屏幕上的一个方块。
程序blkctrl1.c下载链接:
例21:
程序blkctr12.c演示了如何用bioskey
(1)检测键盘缓冲区从而控制方块做随机运动。
程序blkctrl2.c下载链接:
除了使用bioskey()控制键盘外,还可以用键盘中断来控制键盘。
使用键盘中断不仅可以读取bioskey()无法读取的键如Ctrl、Shift、Alt、CapsLock等,而且可以在用户按下某个键的瞬间作出实时响应。
例22:
程序blkctr13.c演示了如何用键盘中断控制方块的移动。
程序blkctrl3.c下载链接:
7.2鼠标输入
鼠标要用到int33h中断