// 注:程序扩展名为.CPP,必须在TC++ for dos 或BC++ for dos 下运行(TC2.0下会出错)
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <mem.h>
#include <bios.h>
#include <conio.h>
#define LineSpace 2 /*行距*/
#define WinW 17*16 /*定义窗口的宽度*/
#define WinH (LineSpace+16)*7+5 /*窗口的宽度*/
#define WinX 30 /*屏幕窗口的起始坐标*/
#define WinY 30
#define BKCOLOR BLUE //开始时的背景色
#define FORECOLOR WHITE //字符前景色
#define BORLDCOLOR RED //屏幕边框色
#define DelayTime 10
#define StartUpLine '^' //上画线开始
#define StartDownLine '_' //下画线开始
#define EndUpLine 'U' //上画线结束
#define EndDownLine 'D' //下画线结束
#define SetForeColorVal 'C' //设置前景色
#define SetBkColorVal 'B' //设置背景色
#define ControlCommand '\\' //控制命令所用字符
#define ESC 0x011b
#define STYLENUM 10 //显示特技类型个数
#define MyWait() { delay(DelayTime);\
if (bioskey(1))\
{ if(bioskey(1)!=ESC) bioskey(0);\
break;\
}\
}
enum InitRetVal
{ /*初始化返回值定义*/
InitOK,
OpenASC16Error,
OpenHZK16Error,
MallocError
};
void SetShowMode(int mode) /*设置显示模式*/
{
union REGS r;
r.h.al=mode;
r.h.ah=0;
int86(0x10,&r,&r);
}
void ClearScreen(int x,int y,int w,int h,int color)
{
int i,j;
for(i=0;i<h;i++)
for(j=0;j<w;j++)
pokeb(0xa000,(y+i)*320+x+j,color);
}
unsigned int inkey(int delaytime)
{
int i;
for(i=0;i<delaytime;i++)
{
delay(1);
if (bioskey(1))
return(bioskey(0));
}
return(0);
}
class VDC
{
private :
int VDCWidth; /*虚拟屏幕内存的宽度*/
int VDCHight; /*高度*/
int ForeColor; //前景色
int BkColor; //背景色
int DownLine; //下画线
int UpLine; //上画线
unsigned char *VDCBuf; /*屏幕内存保存处*/
FILE *LibFp; //汉字库指针
FILE *AscFp; //ASC字库指针
public:
void SetBkColor(int color); //设置显示字符的背景色
void SetForeColor(int color); //设置前景色
void SetDownLineStyle(int i); //设置下画线属性
void SetUpLineStyle(int i); //设置上画线属性
int InitVDC(int w, int h,int color,int bkcolor);//初始化VDC
void CopyVDCToScreen(int x,int y,int style);//将VDC内容复制到屏幕
void ClearVDC(int x,int y,int w,int h,int color);//在VDC中清一矩形
void ClearAllVDC(int color); //清除所有的VDC
void ShowText(int x,int y,unsigned char *string);//显示字符串
void DrawPixel(int x,int y); //在VDC中,画一点
void BitBlt(int x,int y,int w,int h,int ScreenX,int ScreenY); //将VDC矩形区域复制到屏幕上
~VDC() { if(VDCBuf!=NULL) delete VDCBuf; fclose(LibFp); fclose(AscFp);}
};
void VDC::SetBkColor(int color) //设置显示字符的背景色
{
BkColor=color;
}
void VDC::SetForeColor(int color) //设置前景色
{
ForeColor=color;
}
void VDC::SetDownLineStyle(int i) //设置下画线属性
{
DownLine=i;
}
void VDC::SetUpLineStyle(int i) //设置上画线属性
{
UpLine=i;
}
/*******************************************************/
/* 函数作用:在虚拟屏幕中显示字符串 */
/* 入口参数:int x,int y, 显示的坐标 */
/* unsigned char *string, 显示的字符串 */
/*******************************************************/
void VDC::ShowText(int x,int y,unsigned char *string) /*显示的字符串*/
{
int i,j,z,s,LineNum;
unsigned char c,mode[32];
long offset;
int n,IsUse;
while(*string)
{
IsUse=0;
c=*string;
if (c==ControlCommand)
{
IsUse=1;
switch(*(string+1))
{
case StartUpLine: //上画线开始
string+=2;
UpLine=1;
break;
case EndUpLine: //结束上画线
string+=2;
UpLine=0;
break;
case StartDownLine: //开始下画线
string+=2;
DownLine=1;
break;
case EndDownLine: //结束下画线
string+=2;
DownLine=0;
break;
case SetForeColorVal: //设置前景色
ForeColor=*(string+2)-'0';
string+=3;
break;
case SetBkColorVal: //设置背景色
BkColor=*(string+2)-'0';
string+=3;
break;
case '\\': //若后一字符为'\',表示此为一个'\'
string++;
IsUse=0;
break;
default: //其它字符,则没有用到
IsUse=0;
break;
}
}
if (IsUse) continue;
if (c>0x80) /*为汉字*/
{
offset=((c-0xa1)*94+(*(string+1)-0xa1))*32L;
fseek(LibFp,offset,SEEK_SET);
fread(mode,32,1,LibFp);
string+=2;
if (x+16>VDCWidth) //若显示该汉字超过指定的宽度,则换下一行显示
{
x=0;
y+=16+LineSpace;
}
if (y>=VDCHight)
break; //若下一行起始位置达到高度,则退出
else
LineNum=(VDCHight-y>16)? 16:VDCHight-y;
//当前可显示多少行
for(j=0;j<LineNum;j++) /*将该汉字写入VDC表示的内存中*/
{
for(z=0;z<2;z++)
for(s=0;s<8;s++,x++)
if (mode[j*2+z]>>(7-s) & 1) /*对应有位为1,则用前景色表示*/
VDCBuf[VDCWidth*y+x]=ForeColor;
else //否则用背景色表示
VDCBuf[VDCWidth*y+x]=BkColor;
y++;x-=16;
}
y-=LineNum;x+=16;
}
else //为半角字符
{
fseek(AscFp,c*16,SEEK_SET);
fread(mode,1,16,AscFp);
string++;
/*取该汉字的字模*/
if (x+8>VDCWidth)
{
x=0;
y+=16+LineSpace;
}
if (y>=VDCHight)
break;
else
LineNum=(VDCHight-y>16) ? 16:VDCHight-y;
for(j=0;j<LineNum;j++)
/*将该汉字写入VDC表示的内存中*/
{
for(s=0;s<8;s++,x++)
if (mode[j]>>(7-s) & 1) /*对应有位为1,则用前景色表示*/
VDCBuf[VDCWidth*y+x]=ForeColor;
else /*否则用背景色表示*/
VDCBuf[VDCWidth*y+x]=BkColor;
y++;x-=8;
}
y-=LineNum;x+=8;
}
LineNum=(c>0x7f)? 16:8;
if (DownLine) //下画线为真,在此汉字下画线
for(i=0;i<LineNum;i++)
DrawPixel(x-LineNum+i,y+15);
if (UpLine) //上画线为真,在此汉字下画线
for(i=0;i<LineNum;i++)
DrawPixel(x-LineNum+i,y);
}
}
/**************************************************/
/* 函数作用:建立虚拟屏幕 */
/* 入口参数:w,h 屏幕的宽度和高度 */
/* color 字符前景色 */
/* bkcolor 字符背景色 */
/*************************************************/
int VDC::InitVDC( int w, int h,int color,int bkcolor)
{
LibFp=fopen("d:\\HZK16","rb");
if (LibFp==NULL)
return(OpenHZK16Error);
AscFp=fopen("d:\\ASC16","rb");
if (AscFp==NULL) //asc16不能打开
{
fclose(LibFp);
return(OpenASC16Error);
}
VDCWidth=w;
VDCHight=h;
UpLine=0;
DownLine=0;
ForeColor=color;
BkColor=bkcolor;
VDCBuf=new (unsigned char)(w*h);
if (VDCBuf==NULL) //内存分配失败
{
fclose(LibFp); //关闭打开的文件
fclose(AscFp);
return(MallocError);
}
ClearAllVDC(BkColor);
return(InitOK); //初始化成功
}
/*****************************************************/
/* 函数作用:将虚拟屏幕清一矩形区域 */
/* 入口参数:x,y 虚拟屏幕的起始坐标 */
/* w,h 矩形的宽和高 */
/* color 清后区域的色彩 */
/***************************************************/
void VDC::ClearVDC(int x,int y,int w,int h,int color)
{
int i;
for(i=0;i<h;i++)
memset(&VDCBuf[(y+i)*VDCWidth+x],color,w);
}
//将整个虚拟屏幕清成color色
void VDC::ClearAllVDC(int color)
{
memset(VDCBuf,color,VDCWidth*VDCHight);
}
/*VDC中画一点*/
void VDC::DrawPixel(int x,int y)
{
if (!(x>VDCWidth || x<0 ||y>VDCHight||y<0))
VDCBuf[y*VDCWidth+x]=ForeColor;
}
/************************************************/
/* 函数作用:将虚拟屏幕区域内容复制到屏幕上 */
/* 入口参数:x,y 虚拟屏幕的起始坐标 */
/* w,h 欲复制区域的宽度、高度 */
/* ScreenX,ScreenY 物理屏幕的起始位置 */
/************************************************/
void VDC::BitBlt(int x,int y,int w,int h,int ScreenX,int ScreenY)
{
int i;
for (i=0;i<h;i++)
movedata(FP_SEG(&(VDCBuf[(y+i)*VDCWidth+x])),
FP_OFF(&(VDCBuf[(y+i)*VDCWidth+x])),
0xa000,(ScreenY+i)*320+ScreenX,w);
}
/*****************************************************/
/* 函数作用:将虚拟屏幕的内容全部复制到物理屏幕上 */
/* 入口参数:ScreenX,ScreenY 物理屏幕的起始坐标 */
/* style 复制类型 */
/* 说 明:此类型选择时,将动态产生显示特技,若不选 */
/* 择,将快速复制屏幕上 */
/*****************************************************/
void VDC::CopyVDCToScreen(int ScreenX,int ScreenY,int style=24)
{
int i,j,scanline,w,h;
switch(style)
{
case 0: //从下向上
for (i = VDCHight -1;i>=0;i--)
{
BitBlt(0,i,VDCWidth,1,ScreenX,i+ScreenY);
MyWait();
}
break;
case 1: //从左向右
for (i = 0 ;i<VDCWidth ;i++)
{
BitBlt(i,0,1,VDCHight,ScreenX+i,ScreenY);
MyWait();
}
break;
case 2: //从上下向中央
for (i = 0 ; i<VDCHight / 2 ;i++)
{
j = VDCHight - i-1;
BitBlt( 0, i, VDCWidth, 1, ScreenX, ScreenY+i);
BitBlt( 0, j, VDCWidth, 1, ScreenX,ScreenY+ j);
MyWait();
}
break;
case 3: //由上而下成百叶窗口
scanline = 3 + random(6);
for (i = 0 ;i<scanline;i++)
for (j = i ; j<VDCHight;j+=scanline)
{
BitBlt( 0, j, VDCWidth, 1,ScreenX, ScreenY+j);
MyWait();
}
break;
case 4: //从左向右成百叶窗显示
scanline = 3 + random( 6);
for (i = 0 ;i<scanline;i++)
for(j = i ; j<VDCWidth ;j+=scanline)
{
BitBlt( j, 0, 1, VDCHight,ScreenX+j, ScreenY);
MyWait();
}
break;
case 5 : //由中央扩展到四周
j = 0;
for(i = 0 ;i<VDCHight / 2;i++)
{
BitBlt(VDCWidth/2-j,VDCHight/2-i,2*j,2*i,
ScreenX+ VDCWidth/2-j,ScreenY+VDCHight/2-i);
j = (VDCHight/2+i*VDCWidth) / VDCHight;
MyWait();
}
break;
case 6 : // 从右向左流动
for(i = 0 ;i< VDCWidth;i++)
{
BitBlt(0,0,i,VDCHight,ScreenX+VDCWidth-i,ScreenY);
MyWait();
}
break;
case 7 : //从中央同时向左右流动
for(i = 0 ;i< VDCWidth / 2;i++)
{
BitBlt(0,0,i,VDCHight,ScreenX+VDCWidth/2-i,ScreenY);
BitBlt(VDCWidth-i,0,i,VDCHight,VDCWidth/2+ScreenX,ScreenY);
MyWait();
}
break;
case 8 : //从左上角流动到右下角
i = 0;
for (j = 0 ;j<VDCWidth;j++)
{
BitBlt(VDCWidth-j,VDCHight-i,j,i,ScreenX,ScreenY);
i = (j * VDCHight+VDCWidth/2) / VDCWidth;;
MyWait();
}
break;
case 9: //成碎片显示
for (scanline=0;scanline<(VDCWidth*VDCHight/7);scanline++)
{
i=random(VDCWidth);
j=random(VDCHight);
w=random(6)+4;
h=random(6)+4;
if (i+w>=VDCWidth) w=1;
if (j+h>=VDCHight) h=1;
BitBlt(i,j,w,h,ScreenX+i,ScreenY+j);
if(kbhit()) break; /*若用户按下任意键,退出*/
}
break;
}
BitBlt(0,0,VDCWidth,VDCHight,ScreenX,ScreenY);
}
void main()
{
int start,bkcolor;
unsigned int key;
VDC vDC;
unsigned char *text=
"\\_ 长\\D\\^夜空\\U虚使我怀旧事,\
明月朗相对念母亲。父母亲爱心,柔善象碧玉,怀念怎不悲莫禁。\
长夜空虚枕冷夜半泣,遥路远碧海是我心,\\C5父母\\C7\\B4亲爱\
心。柔善象碧玉,常在心里问何日报,亲恩应该报,应该识取孝道\
。唯独我离别无abc法慰亲旁,轻弹曲子梦中送。";
int style,oldstyle,i;
if (vDC.InitVDC(WinW,WinH,FORECOLOR,BKCOLOR)!=InitOK)
{
puts("\n\7VDC init error.\n");
exit(0);
}
SetShowMode(0x13);/*设置320*200*256色模式*/
ClearScreen(0,0,320,200,WHITE); //将整个屏幕清成白色
//将欲作为窗口的矩形区域置成带投影的窗口
ClearScreen(WinX+4,WinY+4,WinW,WinH,BLACK);
//窗口四周为红边
ClearScreen(WinX-1,WinY-1,WinW+2,WinH+2,BORLDCOLOR);
//窗口为蓝色
ClearScreen(WinX,WinY,WinW,WinH,BKCOLOR);
//将虚拟屏幕背景色置成BKCOLOR
//在虚拟屏幕上显示信息
bkcolor=BKCOLOR;
while(1)
{
vDC.ShowText(0,6,text); //显示文本信息
vDC.ClearVDC(0,0,WinW,5,bkcolor);
vDC.CopyVDCToScreen(WinX,WinY,random(STYLENUM+1));
key=inkey(500);
if (key==ESC) break; //按下ESC,退出
bkcolor=random(256);
vDC.ClearAllVDC(bkcolor);
vDC.SetBkColor(bkcolor);
ClearScreen(WinX,WinY,WinW,WinH,BKCOLOR);
}
SetShowMode(0x3);
exit(0);
}