BMP文件初步使用笔记

BMP文件
在c语言图形编程中,640*480+16色是极其常用的模式,具有足够的分辨率,且为大多数显卡所支持,下面将我最近在这一模式下使用16色bmp文件的经验随手记下来(后来也扩展到了256色,不过以16色为基础):
一.BMP文件格式分析以及显示
BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。
BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。其结构定义如下:
typedef struct tagBITMAPFILEHEADER
{
WORDbfType; // 位图文件的类型,必须为BM
DWORD bfSize; // 位图文件的大小,以字节为单位
WORDbfReserved1; // 位图文件保留字,必须为0
WORDbfReserved2; // 位图文件保留字,必须为0
DWORD bfOffBits; // 位图数据的起始位置,以相对于位图
// 文件头的偏移量表示,以字节为单位
} BITMAPFILEHEADER;
3. 位图信息头
BMP位图信息头数据用于说明位图的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; // 本结构所占用字节数
LONGbiWidth; // 位图的宽度,以像素为单位
LONGbiHeight; // 位图的高度,以像素为单位
WORD biPlanes; // 目标设备的级别,必须为1
WORD biBitCount// 每个像素所需的位数,必须是1(双色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage; // 位图的大小,以字节为单位
LONGbiXPelsPerMeter; // 位图水平分辨率,每米像素数
LONGbiYPelsPerMeter; // 位图垂直分辨率,每米像素数
DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数
DWORD biClrImportant;// 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;
4. 颜色表
颜色表用于说明位图中的颜色,它有若干个表项,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。RGBQUAD结构的定义如下:

typedef struct tagRGBQUAD {
BYTErgbBlue;// 蓝色的亮度(值范围为0-255)
BYTErgbGreen; // 绿色的亮度(值范围为0-255)
BYTErgbRed; // 红色的亮度(值范围为0-255)
BYTErgbReserved;// 保留,必须为0
} RGBQUAD;
颜色表中RGBQUAD结构数据的个数有biBitCount来确定:
当biBitCount=1,4,8时,分别有2,16,256个表项;
当biBitCount=24时,没有颜色表项。
位图信息头和颜色表组成位图信息,BITMAPINFO结构定义如下:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader; // 位图信息头
RGBQUAD bmiColors[1]; // 颜色表
} BITMAPINFO;
5. 位图数据
位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:
当biBitCount=1时,8个像素占1个字节;
当biBitCount=4时,2个像素占1个字节;
当biBitCount=8时,1个像素占1个字节;
当biBitCount=24时,1个像素占3个字节;
Windows规定一个扫描行所占的字节数必须是4的倍数(即以long为单位),不足的以0填充,一个扫描行所占的字节数计算方法:
DataSizePerLine= (biWidth* biBitCount+31)/8;
// 一个扫描行所占的字节数
DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数
位图数据的大小(不压缩情况下):
DataSize= DataSizePerLine* biHeight;
在实际操作中采用了一些简化的方法来进行图像的显示。显示图像文件的完全过程如下:
1、 打开图像文件
2、 分析文件头,得到高、宽、色深等信息
3、 转到位图数据区
4、 读取一位像素数据
5、 根据数据中的颜色信息画点
6、 重复4、5的操作,直到数据区结尾
这里有一个需要注意地方的是BMP文件数据的记录顺序在扫描行内是从左到右,扫描行之间是从下到上。这与屏幕上的坐标是不同的,需要进行坐标映射。

二.16色位图文件的显示
位图文件有2色、16色、256色(8位)、16位色、24位色、32位色等色度,分别指一个像素位所存储数据的颜色种类,颜色种类越多,图像就越逼真,但同时也使得图像文件增大,这就需要考虑一种能满足显示要求并使图像文件尽可能小的折衷方案。由于所采用的显示器最多支持8色、640*480分辨率,决定使用640*480的16色位图。
在实践中遇到几个值得注意的地方。
一是如何将BMP格式RGB颜色数据转换为putpixel()函数对应的颜色,没有采用通常的设置调色板的方法,而是设置了一个函数,直接将其映射过来。由于只有16种颜色,这是一个可以接受的方案:
int changecolor(unsigned char c)
{int co;
if (c==0x00) co=16;
if (c==0x0f) co=15;
if (c==0x07) co=16;/*8灰色变黑色*/
if (c==0x08) co=10;/*7背景*/
if (c==0x01) co=4;
if (c==0x09) co=12;
if (c==0x03) co=6;
if (c==0x0b) co=14;
if (c==0x02) co=2;
if (c==0x0a) co=10;
if (c==0x06) co=3;
if (c==0x0e) co=11;
if (c==0x04) co=1;
if (c==0x0c) co=9;
if (c==0x05) co=5;
if (c==0x0d) co=13;
return co;
};
二是C语言文件流系统一次只能读入一个字节数据,但16色BMP图像每一像素只有4位即半个字节长,这样在遇到扫描行像素为奇数时一般会出现问题。经过反复试验,得出一个经验修正量:ofs=(8-width%8)%8,将这个修正量加到文件的实际扫描行像素宽度上就能简单解决这一问题。
下面给出16色位图文件的具体显示方法:
void putbmp1(char *name,int left,int top,int putwidth,int putheight)
{ FILE *fp
int x,y,px,py,ofs;
long width,height;
unsigned char c,c1,c2;
Squeeze_Mouse(MOUSE_HIDE,0,0,0); //隐藏鼠标指针
if(top<1)top=1;
if(left<1)left=1;
if(putwidth>640) putwidth=640;
if(putheight>480) putwidth=480;
if(putwidth<left) putwidth=left;
if(putheight<top) putwidth=top;
fp = fopen(name,"rb");
fseek(fp,18,SEEK_SET);
fread(&width,4,1,fp);
fseek(fp,22,SEEK_SET);
fread(&height,4,1,fp);
fseek(fp,118,SEEK_SET);
ofs=(8-width%8)%8;
for(y=0;y<height;y++)
for(x=0;x<(width+ofs);x++)
{c=fgetc(fp);
c1=c<<4;
c1=c1>>4;
c2=c>>4;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c2));
x++;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c1));
}
fclose(fp);
Squeeze_Mouse(MOUSE_SHOW,0,0,0);//显示鼠标指针
return;
};

上面引用文章2,其实质解决了bmp文件的显示问题,但速度却太慢了;另外,640*480 16色图片不压缩时大约150k,应想办法进行压缩。

三.提高16色位图文件的显示速率
在引用文章2中提到的16色位图文件的显示方法,经测试是可以稳定的完成16色位图文件的显示的。但还存在一个明显的缺陷,即显示速度太慢,显示一张640*480的图片竟需要0.5~0.8秒,这就要求对显示速度进行改进。
显示时间大部分是花在putpixel()函数上,由于它了调用BIOS中断,使执行速度不高,不过平时显示少量的像素时无法察觉到,当调用大量的putpixel()时,这个问题就暴露出来。解决的方案是:大部分窗口,属于以背景为主色的图片,采取的办法是先清背景,再画除背景外部分,也就是在画点之前,先检测这个像素是否是背景色,如是就不画,否则才画点,在这一类窗口中,非背景色像素所占的比例一般不超过10%,所以采用这一方法可使速度提高将近1个数量级。
对于以文字为主的图片窗口,如panel等,,采取的办法是先清背景,再画文字,也就是在画点之前,先检测这个像素是否是文字色,如是就画点,否则不画。原理和效果都和前面方案相似。
源代码参见putbmp()和putbmp2()。

四.我的16色位图函数库
/*位图*/
#define WZCOLOR 16
#define BJCOLOR 10
int changecolor(unsigned char c)
{int co;
if (c==0x00) co=16;
if (c==0x0f) co=15;
if (c==0x07) co=16;/*8灰色变黑色*/
if (c==0x08) co=10;/*7背景*/
if (c==0x01) co=4;
if (c==0x09) co=12;
if (c==0x03) co=6;
if (c==0x0b) co=14;
if (c==0x02) co=2;
if (c==0x0a) co=10;
if (c==0x06) co=3;
if (c==0x0e) co=11;
if (c==0x04) co=1;
if (c==0x0c) co=9;
if (c==0x05) co=5;
if (c==0x0d) co=13;
return co;
};

void putbmp(char *name,int left,int top,int putwidth,int putheight)
{ FILE *fp;/*为了提高以背景为主色的图片速度,先清背景,再画除背景外部分,用在大部分窗口*/
int x,y,px,py,ofs;
long width,height;
unsigned char c,c1,c2;
static int flag=1;
if(flag==1){flag=0;setfillstyle(SOLID_FILL,BJCOLOR);}
Squeeze_Mouse(MOUSE_HIDE,0,0,0);
bar(left,top,putwidth,putheight);
if(top<1)top=1;
if(left<1)left=1;
if(putwidth>640) putwidth=640;
if(putheight>480) putwidth=480;
if(putwidth<left) putwidth=left;
if(putheight<top) putwidth=top;
fp = fopen(name,"rb");
fseek(fp,18,SEEK_SET);
fread(&width,4,1,fp);
fseek(fp,22,SEEK_SET);
fread(&height,4,1,fp);
fseek(fp,118,SEEK_SET); /*printf("%ld,%ld",width,height);quit(0);*/
ofs=(8-width%8)%8;
for(y=0;y<height;y++)
for(x=0;x<(width+ofs);x++)
{
c=fgetc(fp);
c1=c<<4;
c1=c1>>4;
c2=c>>4;
px=x+left;
py=height-y+top;
if((changecolor(c2)!=BJCOLOR)&&(px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c2));
x++;
px=x+left;
py=height-y+top;
if((changecolor(c1)!=BJCOLOR)&&(px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c1));

}
fclose(fp);
Squeeze_Mouse(MOUSE_SHOW,0,0,0);
return;
};

void putbmp1(char *name,int left,int top,int putwidth,int putheight)
{ FILE *fp;/*不使用任何提速手段,直接画,用在进度条上,如用putbmp(),会闪烁*/
int x,y,px,py,ofs;
long width,height;
unsigned char c,c1,c2;
Squeeze_Mouse(MOUSE_HIDE,0,0,0);
if(top<1)top=1;
if(left<1)left=1;
if(putwidth>640) putwidth=640;
if(putheight>480) putwidth=480;
if(putwidth<left) putwidth=left;
if(putheight<top) putwidth=top;
fp = fopen(name,"rb");
fseek(fp,18,SEEK_SET);
fread(&width,4,1,fp);
fseek(fp,22,SEEK_SET);
fread(&height,4,1,fp);
fseek(fp,118,SEEK_SET); /*printf("%ld,%ld",width,height);quit(0);*/
ofs=(8-width%8)%8;
for(y=0;y<height;y++)
for(x=0;x<(width+ofs);x++)
{
c=fgetc(fp);
c1=c<<4;
c1=c1>>4;
c2=c>>4;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c2));
x++;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c1));

}
fclose(fp);
Squeeze_Mouse(MOUSE_SHOW,0,0,0);
return;
};

void putbmp2(char *name,int left,int top,int putwidth,int putheight)
{ FILE *fp;/*为了提高以文字的图片速度,先清背景,再画文字,用在panel,文字上*/
int x,y,px,py,ofs;
long width,height;
unsigned char c,c1,c2;
static int flag=1;
if(flag==1){flag=0;setfillstyle(SOLID_FILL,BJCOLOR);}
Squeeze_Mouse(MOUSE_HIDE,0,0,0);
bar(left,top,putwidth,putheight);
if(top<1)top=1;
if(left<1)left=1;
if(putwidth>640) putwidth=640;
if(putheight>480) putwidth=480;
if(putwidth<left) putwidth=left;
if(putheight<top) putwidth=top;
fp = fopen(name,"rb");
fseek(fp,18,SEEK_SET);
fread(&width,4,1,fp);
fseek(fp,22,SEEK_SET);
fread(&height,4,1,fp);
fseek(fp,118,SEEK_SET); /*printf("%ld,%ld",width,height);quit(0);*/
ofs=(8-width%8)%8;
for(y=0;y<height;y++)
for(x=0;x<(width+ofs);x++)
{
c=fgetc(fp);
c1=c<<4;
c1=c1>>4;
c2=c>>4;
px=x+left;
py=height-y+top;
if((changecolor(c2)==WZCOLOR)&&(px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))
putpixel(px,py,changecolor(c2));
x++;
px=x+left;
py=height-y+top;
if((changecolor(c1)==WZCOLOR)&&(px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))
putpixel(px,py,changecolor(c1));

}
fclose(fp);
Squeeze_Mouse(MOUSE_SHOW,0,0,0);
return;
};

void putbmp3(char *name,long h)
{ FILE *fp;/*显示256色位图,用于帮助说明中的大位图*/
int x=1,y=1;
static flag=1;
if(h<0)h=0;
fp=fopen(name,"rb");
fseek(fp,1078+h*640,SEEK_SET);
if(flag){setfillstyle(SOLID_FILL,BJCOLOR);
flag=0;}
bar(16,38,454,425);
while(!feof(fp))
{char c;
c=fgetc(fp);
if(c==0)
{int px=x,py=480-y;
if((px>16)&&(px<454)&&(py>38)&&(py<425))putpixel(px,py,c);
}
x++;
if(x==641)x=1,y++;
if(y==481){fclose(fp);break;}
}
return;
};

void putbmp4(char *name,long h)
{ FILE *fp;/*显示256色位图,用于表格的背景*/
int x=1,y=1;
static flag=1;
if(h<0)h=0;
fp=fopen(name,"rb");
fseek(fp,1078+h*640,SEEK_SET);
if(flag){setfillstyle(SOLID_FILL,BJCOLOR);
flag=0;}
bar(23,112,620,420);
while(!feof(fp))
{char c;
c=fgetc(fp);
if(c==0)
{int px=x,py=480-y;
if((px>2)&&(px<594)&&(py>56)&&(py<358))putpixel(px+15,py+55,c);
}
x++;
if(x==641)x=1,y++;
if(y==481){fclose(fp);break;}
}
return;
};


/*位图*/

函数库中的putbmp()已经达到可用的水平,主要因为使用了文章3中的做法,但还是有不足的,一是只有在显示以颜色简单的文件是才能有效,2是仍没对位图进行压缩。
这对于应付我的毕业专题已经绰绰有余,所以在《激光制导炸弹智能检测设备》的界面中,得到了应用,并取得了很好的效果。
五.去掉能想象到的缺点
一, 速度的极限
比照320*200 256色下的情况,640*480 16色因屏幕颜色空间大于64k而无法用直接写显存方式绘图,因而无法照抄前者的绘图方式。于是我仿照这种思路将平均屏幕分成3部分,
分块存储及绘制,并定义了一种新的图形文件格式,专门针对640*480 16色c图形库使用的。非常简单,就是将y轴1-160,160-320,320-480三块640宽的图顺序存在一个后缀img的文件中。画时就顺序读出,用putimg画上去。
以下是转换程序,bmp2img.c:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
#include<dos.h>
#include<math.h>


/*图形*/
void init() /*初始化图形模式*/
{int driver=DETECT,mode=0;

initgraph(&driver,&mode,"");
return;
};

void quit() /*退出图形模式*/
{closegraph();
exit(0);
};
/*图形*/

 


/*位图*/
int changecolor(unsigned char c)
{int co;
if (c==0x00) co=16;
if (c==0x0f) co=15;
if (c==0x07) co=8;/*灰色*/
if (c==0x08) co=7;/*背景*/
if (c==0x01) co=4;
if (c==0x09) co=12;
if (c==0x03) co=6;
if (c==0x0b) co=14;
if (c==0x02) co=2;
if (c==0x0a) co=10;
if (c==0x06) co=3;
if (c==0x0e) co=11;
if (c==0x04) co=1;
if (c==0x0c) co=9;
if (c==0x05) co=5;
if (c==0x0d) co=13;
return co;
};

void putbmp(char *name,int left,int top,int putwidth,int putheight)
{ FILE *fp;/*不使用任何提速手段,直接画*/
int x,y,px,py,ofs;
long width,height;
unsigned char c,c1,c2;
if(top<1)top=1;
if(left<1)left=1;
if(putwidth>640) putwidth=640;
if(putheight>480) putwidth=480;
if(putwidth<left) putwidth=left;
if(putheight<top) putwidth=top;
fp = fopen(name,"rb");
fseek(fp,18,SEEK_SET);
fread(&width,4,1,fp);
fseek(fp,22,SEEK_SET);
fread(&height,4,1,fp);
fseek(fp,118,SEEK_SET);
ofs=(8-width%8)%8;
for(y=0;y<height;y++)
for(x=0;x<(width+ofs);x++)
{
c=fgetc(fp);
c1=c<<4;
c1=c1>>4;
c2=c>>4;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c2));
x++;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c1));

}
fclose(fp);
return;
};

main()
{int i;
char buf1[51206];

init();
putbmp("f1.bmp",1,1,640,480);
getch();

getimage(1,1,639,160,buf1);

{FILE *fp;
long i;
fp=fopen("t.img","wb");
for(i=0;i<51206;i++)
{fputc(buf1[i],fp);
}
fclose(fp);
}

getimage(1,161,639,320,buf1);

{FILE *fp;
long i;
fp=fopen("t.img","ab");
for(i=0;i<51206;i++)
{fputc(buf1[i],fp);
}
fclose(fp);
}

getimage(1,321,639,479,buf1);

{FILE *fp;
long i;
fp=fopen("t.img","ab");
for(i=0;i<51206;i++)
{fputc(buf1[i],fp);
}
fclose(fp);
}


bar(1,1,640,480);
getch();

/*
{FILE *fp1;
long i;
fp1=fopen("t.img","rb");

for(i=0;i<51206;i++)
{buf1[i]=fgetc(fp1);
}
putimage(1,1,buf1,0);

for(i=0;i<51206;i++)
{buf1[i]=fgetc(fp1);
}
putimage(1,161,buf1,0);

for(i=0;i<51206;i++)
{buf1[i]=fgetc(fp1);
}
putimage(1,321,buf1,0);

fclose(fp1);
}


getch(); */
closegraph();

}

以下是绘制时的程序,putimg.c:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
#include<dos.h>
#include<math.h>


/*图形*/
void init() /*初始化图形模式*/
{int driver=DETECT,mode=0;

initgraph(&driver,&mode,"");
return;
};

void quit() /*退出图形模式*/
{closegraph();
exit(0);
};
/*图形*/

 


main()
{int i;
char buf1[51206];

init();


{FILE *fp1;
long i;
fp1=fopen("t.img","rb");

for(i=0;i<51206;i++)
{buf1[i]=fgetc(fp1);
}
putimage(1,1,buf1,0);

for(i=0;i<51206;i++)
{buf1[i]=fgetc(fp1);
}
putimage(1,161,buf1,0);

for(i=0;i<51206;i++)
{buf1[i]=fgetc(fp1);
}
putimage(1,321,buf1,0);

fclose(fp1);
}


getch();
closegraph();

}

二, 简单的压缩
如名字所示,这种文件使用2个字节为一个单位来存储一段相同的像素,即数量加颜色值,对于检查仪中遇到的图片,这种压缩方式的压缩比一般能超过10。画的时候也极其简单。
代码:bmp2txt.c:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
#include<dos.h>
#include<math.h>


/*图形*/
void init() /*初始化图形模式*/
{int driver=DETECT,mode=0;

initgraph(&driver,&mode,"");
return;
};

/*图形*/
int changecolor(unsigned char c)
{int co;
if (c==0x00) co=16;
if (c==0x0f) co=15;
if (c==0x07) co=8;/*灰色*/
if (c==0x08) co=7;/*背景*/
if (c==0x01) co=4;
if (c==0x09) co=12;
if (c==0x03) co=6;
if (c==0x0b) co=14;
if (c==0x02) co=2;
if (c==0x0a) co=10;
if (c==0x06) co=3;
if (c==0x0e) co=11;
if (c==0x04) co=1;
if (c==0x0c) co=9;
if (c==0x05) co=5;
if (c==0x0d) co=13;
return co;
};

void putbmp(char *name,int left,int top,int putwidth,int putheight)
{ FILE *fp;/*不使用任何提速手段,直接画*/
int x,y,px,py,ofs;
long width,height;
unsigned char c,c1,c2;
if(top<1)top=1;
if(left<1)left=1;
if(putwidth>640) putwidth=640;
if(putheight>480) putwidth=480;
if(putwidth<left) putwidth=left;
if(putheight<top) putwidth=top;
fp = fopen(name,"rb");
fseek(fp,18,SEEK_SET);
fread(&width,4,1,fp);
fseek(fp,22,SEEK_SET);
fread(&height,4,1,fp);
fseek(fp,118,SEEK_SET);
ofs=(8-width%8)%8;
for(y=0;y<height;y++)
for(x=0;x<(width+ofs);x++)
{
c=fgetc(fp);
c1=c<<4;
c1=c1>>4;
c2=c>>4;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c2));
x++;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c1));

}
fclose(fp);
return;
};

main()
{int x,y;
int a,b;
int c=1;
int n=0;
FILE *fp;
init();
putbmp("f1.bmp",1,1,640,480);
fp=fopen("f2.txt","wb");/*画图*/
a=b=getpixel(1,1);
for(y=1;y<=480;y++)
{for(x=1;x<=640;x++)
{a=getpixel(x,y);
if(a==b){c++;}
if(a!=b){
fputc(c,fp);
fputc(b,fp);
c=1;
}
if(c==255){fputc(c,fp);
fputc(b,fp);
c=0;
}
b=a;
}
}
fclose(fp);
getch();

n=0;/*画图*/
fp=fopen("f2.txt","rb");
for(y=1;y<=480;y++)
{for(x=1;x<=640;x++)
{if(n==0){n=fgetc(fp);
c=fgetc(fp);}
putpixel(x,y,c);
n--;
}
}
fclose(fp);
getch();

closegraph();
}

后来我又作了改进,终于找到一种比较好的屏幕文件格式,它有3个优点:1,逻辑极其简单,绘制,转化代码都在10行以内。2,具有压缩功能,压缩率可以超过10。3,显示速度足够快,而且不针对某一颜色了。这种格式仍叫txt,因为它仍是基于字节的。
这种同时具有简单,足够的性能和通用性的方法应该能广泛的使用。
他是将所有的像素集合都限定在一行中,这样,这个像素集合就变成了直线,画的时候,直接用lineto画直线就行,由于lineto()是直接写显存的,于是速度提高了很多。
代码,值得推荐的算法:bmp2txt2.c

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
#include<graphics.h>
#include<dos.h>
#include<math.h>


/*图形*/
void init() /*初始化图形模式*/
{int driver=DETECT,mode=0;

initgraph(&driver,&mode,"");
return;
};

/*图形*/
int changecolor(unsigned char c)
{int co;
if (c==0x00) co=16;
if (c==0x0f) co=15;
if (c==0x07) co=8;/*灰色*/
if (c==0x08) co=7;/*背景*/
if (c==0x01) co=4;
if (c==0x09) co=12;
if (c==0x03) co=6;
if (c==0x0b) co=14;
if (c==0x02) co=2;
if (c==0x0a) co=10;
if (c==0x06) co=3;
if (c==0x0e) co=11;
if (c==0x04) co=1;
if (c==0x0c) co=9;
if (c==0x05) co=5;
if (c==0x0d) co=13;
return co;
};

void putbmp(char *name,int left,int top,int putwidth,int putheight)
{ FILE *fp;/*不使用任何提速手段,直接画*/
int x,y,px,py,ofs;
long width,height;
unsigned char c,c1,c2;
if(top<1)top=1;
if(left<1)left=1;
if(putwidth>640) putwidth=640;
if(putheight>480) putwidth=480;
if(putwidth<left) putwidth=left;
if(putheight<top) putwidth=top;
fp = fopen(name,"rb");
fseek(fp,18,SEEK_SET);
fread(&width,4,1,fp);
fseek(fp,22,SEEK_SET);
fread(&height,4,1,fp);
fseek(fp,118,SEEK_SET);
ofs=(8-width%8)%8;
for(y=0;y<height;y++)
for(x=0;x<(width+ofs);x++)
{
c=fgetc(fp);
c1=c<<4;
c1=c1>>4;
c2=c>>4;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c2));
x++;
px=x+left;
py=height-y+top;
if((px>0)&&(px<=putwidth)&&(py>0)&&(py<=putheight))putpixel(px,py,changecolor(c1));

}
fclose(fp);
return;
};

main()
{int x,y;
int a,b;
int c=1;
int n=0;
FILE *fp;
init();
putbmp("f1.bmp",1,1,640,480);/*压缩*/
fp=fopen("f2.txt","wb");
a=b=getpixel(1,1);
for(y=1;y<=480;y++)
{for(x=1;x<=640;x++)
{a=getpixel(x,y);
if(a==b){c++;}
if(a!=b){
fputc(c,fp);
fputc(b,fp);
c=1;
}
if(c==255){fputc(c,fp);
fputc(b,fp);
c=0;
continue;
}
if(x==641){fputc(c,fp);
fputc(b,fp);
c=0;
continue;
}
b=a;
}
}
fclose(fp);
getch();

bar(0,0,640,480);/*清空屏幕*/
getch();
n=0;/*画图*/
fp=fopen("f2.txt","rb");
for(y=1;y<=480;)
{x=1;
l:
n=fgetc(fp);
c=fgetc(fp);
setcolor(c);
lineto(x+=n,y);
if(x<=640)goto l;
moveto(1,++y);
}
fclose(fp);
getch();

closegraph();
}
//分离出来的画txt格式图形的函数;
puttxt(char *fn)
{int n,x,y,c;
FILE *fp;
n=0;/*画图*/
fp=fopen(fn,"rb");
for(y=1;y<=480;)
{x=1;
do{n=fgetc(fp);
c=fgetc(fp);
setcolor(c);
lineto(x+=n,y);}
while(x<=640);
moveto(1,++y);
}
fclose(fp);
}

这种方法仍存在的缺点就是没存储文件的大小信息,只支持一种大小即640*480的文件。当然按这个思路加上这个特性也不是难事。
思路:
1, 能从bmp直接不经过屏幕就进行转换的
2, 文件头部加上格式标志和大小信息(long型)
3, 能存储大于640*480的文件
4, 能存储小于640*480的文件
5, 能显示大文件drawtxt(int x,y,nx,ny,width,height);
六.最后的打击
后来上了网,发现原来世界上早就存在很好的函数库了,北航那位哥们的neo使我内心受尽了折磨,思考了很久自己是不是白痴这个严肃的问题。不过那位老兄也是从外国人的源码copy过来的,于是决定毫不客气的copy他的源码。
neo和那些快速函数库取得速度的秘诀就是自己用中断写个dot()画点函数,在此基础上重写line(),之类的函数,对他们进行变态的优化。
在网上看见另一位老兄写的640*480*256色函数库,觉得是有用的,就留下来,简化,改成纯c版本(原来是c++的),记下来,就有了一套小基础绘图库,以后用(无耻吧)。
#if !defined(__GRAPH_H)
#define __GRAPH_H
#include<math.h>
#include<bios.h>
#include<stdio.h>
#include<dos.h>
#include<conio.h>
#include<stdlib.h>

#define PALETTE_MASK 0x3c6
#define PALETTE_REGISTER_RD 0x3c7
#define PALETTE_REGISTER_WR 0x3c8
#define PALETTE_DATA 0x3c9
typedef struct
{
unsigned char red;
unsigned char green;
unsigned char blue;
}RGB_color_typ,RGB_color,*RGB_color_ptr;
RGB_color_typ PaletteBuffer[256];
long DisplayAdd=0xa0000000;
int CUR_PAGE=0;
unsigned char ForColor=WHITE,BkColor=BLACK;
float sin_look[361];
float cos_look[361];
void InitGraph()
{ union REGS r;
r.x.ax=0x4f02;
r.x.bx=0x101;
int86(0x10,&r,&r);
if(r.x.ax!=0x004f)
{ printf("Your video can doesn't support 640*480*256 mode!");
getch();
exit(0);
}
}
void CloseGraph()
{ union REGS r;
r.h.ah=0;
r.h.al=0x03;
int86(0x10,&r,&r);
}
void SelectPage(int Page)
{ union REGS r;
r.x.ax=0x4f05;
r.x.bx=0;
r.x.dx=Page;
int86(0x10,&r,&r);
}
/*void PutPixel(long x,long y)
{ unsigned int page,offset;
long pixel;
pixel=x+(y<<9)+(y<<7);
page=(pixel>>16);
offset=pixel-(page<<16);
if(page!=CUR_PAGE)
{ SelectPage(page);
CUR_PAGE=page;
}
*(unsigned char far *)(DisplayAdd+offset)=ForColor;
}*/
void PutPixel(long x,long y, char Color)
{ unsigned int page,offset;
long pixel;
pixel=x+(y<<9)+(y<<7);
page=(pixel>>16);
offset=pixel-(page<<16);
if(page!=CUR_PAGE)
{ SelectPage(page);
CUR_PAGE=page;
}
*(unsigned char far *)(DisplayAdd+offset)=Color;
};
int GetPixel(long x,long y)
{ unsigned int page,offset;
long pixel;
pixel=x+(y<<9)+(y<<7);
page=(pixel>>16);
offset=pixel-(page<<16);
if(page!=CUR_PAGE)
{ SelectPage(page);
CUR_PAGE=page;
}
return *(unsigned char far *)(DisplayAdd+offset);
}
/*void PutPixelXor(long x,long y)
{
int ScreenColor;
unsigned int page,offset;
long pixel;
pixel=x+(y<<9)+(y<<7);
page=(pixel>>16);
offset=pixel-(page<<16);
if(page!=CUR_PAGE)
{ SelectPage(page);
CUR_PAGE=page;
}
ScreenColor=GetPixel(x,y);
*(unsigned char far *)(DisplayAdd+offset)=ForColor^ScreenColor;
};*/
void PutPixelXor(long x,long y, char Color)
{
int ScreenColor;
unsigned int page,offset;
long pixel;
pixel=x+(y<<9)+(y<<7);
page=(pixel>>16);
offset=pixel-(page<<16);
if(page!=CUR_PAGE)
{ SelectPage(page);
CUR_PAGE=page;
}
ScreenColor=GetPixel(x,y);
*(unsigned char far *)(DisplayAdd+offset)=Color^ScreenColor;
};
void Set_Palette_Register(int index,RGB_color_ptr color)
{
outp(PALETTE_MASK,0xff);
outp(PALETTE_REGISTER_WR,index);
outp(PALETTE_DATA,color->red);
outp(PALETTE_DATA,color->green);
outp(PALETTE_DATA,color->blue);
};
void Get_Palette_Register(int index,RGB_color_ptr color)
{
outp(PALETTE_MASK,0xff);
outp(PALETTE_REGISTER_RD,index);
color->red=inp(PALETTE_DATA);
color->green=inp(PALETTE_DATA);
color->blue=inp(PALETTE_DATA);

};
void Save_Palette_Register(void)
{
int i;
for(i=0;i<256;i++)
{
Get_Palette_Register(i,(RGB_color_ptr)&PaletteBuffer[i]);
};
};
void Restore_Palette_Register(void)
{
int i;
for(i=0;i<256;i++)
{
Set_Palette_Register(i,(RGB_color_ptr)&PaletteBuffer[i]);
};
};
void ClearDevice(void)
{
int index,index0;
RGB_color color;
for(index0=0;index0<64;index0++)
{
for(index=1;index<256;index++)
{
Get_Palette_Register(index,(RGB_color_ptr)&color);
if(color.red!=0)
color.red=color.red-1;
if(color.green!=0)
color.green=color.green-1;
if(color.blue!=0)
color.blue=color.blue-1;
Set_Palette_Register(index,(RGB_color_ptr)&color);
/*delay(1);*/
};
};
};
void GraphicsToWhite(void)
{
int index,index0;
RGB_color color;
for(index0=0;index0<64;index0++)
{
for(index=1;index<256;index++)
{
Get_Palette_Register(index,(RGB_color_ptr)&color);
if(color.red!=63)
color.red=color.red+1;
if(color.green!=63)
color.green=color.green+1;
if(color.blue!=63)
color.blue=color.blue+1;
Set_Palette_Register(index,(RGB_color_ptr)&color);
/*/delay(1);*/
};
};
};
void SetColor(char Color)
{ ForColor=Color;
};
void SetBkColor(char Color)
{ BkColor=Color;
};
void Line(long x1,long y1,long x2,long y2)
{ int i;
if(y1==y2)
{
if(x1<0)x1=0;
if(x2>639)x2=639;
for(i=x1;i<=x2;i++)
PutPixel(i,y2,ForColor);
}
else {
if(y1<0)y1=0;
if(y2>479)y2=479;
for(i=y1;i<=y2;i++)
PutPixel(x2,i,ForColor);
};
};
void BLine(long x0,long y0,long x1,long y1,unsigned char color)
{
int dx,dy;
int index;
int x_inc,y_inc;
int error=0;
dx=x1-x0;
dy=y1-y0;
if(dx>=0)
{
x_inc=1;
}
else
{
x_inc=-1;
dx=-dx;
}
if(dy>=0)
{
y_inc=1;
}
else
{
y_inc=-1;
dy=-dy;
}
if(dx>dy)
{
for(index=0;index<=dx;index++)
{
PutPixel(x0,y0,color);
error+=dy;
if(error>dx)
{
error-=dx;
y0+=y_inc;
}
x0+=x_inc;
}
}
else
{
for(index=0;index<=dy;index++)
{
/**vb_start=color;*/
PutPixel(x0,y0,color);
error+=dx;
if(error>0)
{
error-=dy;
x0+=x_inc;
}
y0+=y_inc;
}
}
}
void Bar(long x1,long y1,long x2,long y2)
{ int i;
for(i=y1;i<=y2;i++)
Line(x1,i,x2,i);
};
void Rectange(long x1,long y1,long x2,long y2)
{
Line(x1,y1,x2,y1);
Line(x1,y2,x2,y2);
Line(x1,y1,x1,y2);
Line(x2,y1,x2,y2);
};
void CreateTables(void)
{
int index;
for(index=0;index<=360;index++)
{
cos_look[index]=(float)cos((double)(index*3.14159/180));
sin_look[index]=(float)sin((double)(index*3.14159/180));
};
};
void Circle(int x,int y,int r,int color)
{
int x0,y0,x1,y1,index;
x0=y0=r/sqrt(2);
for(index=0;index<=360;index++)
{
x1=x0*cos_look[index]-y0*sin_look[index];
y1=x0*sin_look[index]+y0*cos_look[index];
PutPixel(x+x1,y+y1,color);
};

};
void BCircle(int x,int y,int r,int color)
{
int x0,y0,x1,y1,index;
x0=y0=r/sqrt(2);
for(index=0;index<=360;index++)
{
x1=x0*cos_look[index]-y0*sin_look[index];
y1=x0*sin_look[index]+y0*cos_look[index];
PutPixel(x+x1,y+y1,color);
PutPixel(x+x1-1,y+y1,color);
PutPixel(x+x1,y+y1-1,color);
PutPixel(x+x1+1,y+y1,color);
PutPixel(x+x1,y+y1+1,color);
PutPixel(x+x1-1,y+y1-1,color);
PutPixel(x+x1+1,y+y1-1,color);
PutPixel(x+x1+1,y+y1+1,color);
PutPixel(x+x1-1,y+y1+1,color);
};

};
void FillCircle(int x,int y,int r,int color)
{
int index;
for(index=r;index>0;index--)
{
BCircle(x,y,index,color);
};
};
void Circle2(int x_center,int y_center,int radius,int color)
{
int x;
int y,delta;
y=radius;
delta=3-(radius<<1);
for (x=0;x<=y;)
{
PutPixel(x+x_center,y+y_center,color);
PutPixel(x+x_center,-y+y_center,color);
PutPixel(-x+x_center,-y+y_center,color);
PutPixel(-x+x_center,y+y_center,color);
PutPixel(y+x_center,x+y_center,color);
PutPixel(y+x_center,-x+y_center,color);
PutPixel(-y+x_center,-x+y_center,color);
PutPixel(-y+x_center,x+y_center,color);
if (delta<0) delta+=(x<<2)+6;
else { delta+=((x-y)<<2)+10; y--;};
x++;
};
};
double asp_ratio;
void PlotCircle(int x,int y,int x_center,int y_center,int color)
{
double startx,endx,x1,starty,endy,y1;

starty=y*asp_ratio; endy=(y+1)*asp_ratio;
startx=x*asp_ratio; endx=(x+1)*asp_ratio;
for(x1=startx;x1<endx;++x1)
{
PutPixel(x1+x_center,y+y_center,color);
PutPixel(x1+x_center,-y+y_center,color);
PutPixel(-x1+x_center,-y+y_center,color);
PutPixel(-x1+x_center,y+y_center,color);
};
for(y1=starty;y1<endy;++y1)
{
PutPixel(y1+x_center,x+y_center,color);
PutPixel(y1+x_center,-x+y_center,color);
PutPixel(-y1+x_center,-x+y_center,color);
PutPixel(-y1+x_center,x+y_center,color);
};
};
void Ellipse(int x_center,int y_center,int x_radius,int y_radius,int color)
{
register int x,y,delta;
asp_ratio=y_radius;
asp_ratio/=x_radius;
y=x_radius;
delta=3-(x_radius<<1);
for (x=0;x<=y;)
{
PlotCircle(x,y,x_center,y_center,color);
if (delta<0) delta+=(x<<2)+6;
else { delta+=((x-y)<<2)+10; y--;};
x++;
};
};
void LineXor(long x1,long y1,long x2,long y2)
{ int i;
if(y1==y2)
{
if(x1<0)x1=0;
if(x2>639)x2=639;
for(i=x1;i<=x2;i++)
PutPixelXor(i,y2,ForColor);
}
else {
if(y1<0)y1=0;
if(y2>479)y2=479;
for(i=y1;i<=y2;i++)
PutPixelXor(x2,i,ForColor);
};
};
void BLineXor(long x0,long y0,long x1,long y1,unsigned char color)
{
int dx,dy;
int index;
int x_inc,y_inc;
int error=0;
dx=x1-x0;
dy=y1-y0;
if(dx>=0)
{
x_inc=1;
}
else
{
x_inc=-1;
dx=-dx;
}
if(dy>=0)
{
y_inc=1;
}
else
{
y_inc=-1;
dy=-dy;
}
if(dx>dy)
{
for(index=0;index<=dx;index++)
{
PutPixelXor(x0,y0,color);
error+=dy;
if(error>dx)
{
error-=dx;
y0+=y_inc;
}
x0+=x_inc;
}
}
else
{
for(index=0;index<=dy;index++)
{
PutPixelXor(x0,y0,color);
error+=dx;
if(error>0)
{
error-=dy;
x0+=x_inc;
}
y0+=y_inc;
}
}
}
void BarXor(long x1,long y1,long x2,long y2)
{ int i;
for(i=y1;i<=y2;i++)
LineXor(x1,i,x2,i);
};
void RectangeXor(long x1,long y1,long x2,long y2)
{
LineXor(x1,y1,x2,y1);
LineXor(x1,y2,x2,y2);
LineXor(x1,y1,x1,y2);
LineXor(x2,y1,x2,y2);
};
void CircleXor(int x,int y,int r,int color)
{
int x0,y0,x1,y1,index;
x0=y0=r/sqrt(2);
for(index=0;index<=360;index++)
{
x1=x0*cos_look[index]-y0*sin_look[index];
y1=x0*sin_look[index]+y0*cos_look[index];
PutPixelXor(x+x1,y+y1,color);
};

};
void BCircleXor(int x,int y,int r,int color)
{
int x0,y0,x1,y1,index;
x0=y0=r/sqrt(2);
for(index=0;index<=360;index++)
{
x1=x0*cos_look[index]-y0*sin_look[index];
y1=x0*sin_look[index]+y0*cos_look[index];
PutPixelXor(x+x1,y+y1,color);
PutPixelXor(x+x1-1,y+y1,color);
PutPixelXor(x+x1,y+y1-1,color);
PutPixelXor(x+x1+1,y+y1,color);
PutPixelXor(x+x1,y+y1+1,color);
PutPixelXor(x+x1-1,y+y1-1,color);
PutPixelXor(x+x1+1,y+y1-1,color);
PutPixelXor(x+x1+1,y+y1+1,color);
PutPixelXor(x+x1-1,y+y1+1,color);
};

};
void FillCircleXor(int x,int y,int r,int color)
{
int index;
for(index=r;index>0;index--)
{
BCircleXor(x,y,index,color);
};
};
void Circle2Xor(int x_center,int y_center,int radius,int color)
{
int x;
int y,delta;
y=radius;
delta=3-(radius<<1);
for (x=0;x<=y;)
{
PutPixelXor(x+x_center,y+y_center,color);
PutPixelXor(x+x_center,-y+y_center,color);
PutPixelXor(-x+x_center,-y+y_center,color);
PutPixelXor(-x+x_center,y+y_center,color);
PutPixelXor(y+x_center,x+y_center,color);
PutPixelXor(y+x_center,-x+y_center,color);
PutPixelXor(-y+x_center,-x+y_center,color);
PutPixelXor(-y+x_center,x+y_center,color);
if (delta<0) delta+=(x<<2)+6;
else { delta+=((x-y)<<2)+10; y--;};
x++;
};
};
void PlotCircleXor(int x,int y,int x_center,int y_center,int color)
{
double startx,endx,x1,starty,endy,y1;

starty=y*asp_ratio; endy=(y+1)*asp_ratio;
startx=x*asp_ratio; endx=(x+1)*asp_ratio;
for(x1=startx;x1<endx;++x1)
{
PutPixelXor(x1+x_center,y+y_center,color);
PutPixelXor(x1+x_center,-y+y_center,color);
PutPixelXor(-x1+x_center,-y+y_center,color);
PutPixelXor(-x1+x_center,y+y_center,color);
};
for(y1=starty;y1<endy;++y1)
{
PutPixelXor(y1+x_center,x+y_center,color);
PutPixelXor(y1+x_center,-x+y_center,color);
PutPixelXor(-y1+x_center,-x+y_center,color);
PutPixelXor(-y1+x_center,x+y_center,color);
};
};
void EllipseXor(int x_center,int y_center,int x_radius,int y_radius,int color)
{
register int x,y,delta;
asp_ratio=y_radius;
asp_ratio/=x_radius;
y=x_radius;
delta=3-(x_radius<<1);
for (x=0;x<=y;)
{
PlotCircleXor(x,y,x_center,y_center,color);
if (delta<0) delta+=(x<<2)+6;
else { delta+=((x-y)<<2)+10; y--;};
x++;
};
};
void GetImage(long Left,long Top,long Right,long Bottom,char *Buffer)
{
int ImageOffset=0;
unsigned long offset,O,page;
long pixel;
long ImageHigh=Bottom-Top;
long ImageWidth=Right-Left;
offset=Left+(Top<<9)+(Top<<7);
for(Top=0;Top<=ImageHigh;Top++)
{
for(Left=0;Left<=ImageWidth;Left++)
{
pixel=offset+Left;
page=(pixel>>16);
O=pixel-(page<<16);
if(page!=CUR_PAGE)
{
SelectPage(page);
CUR_PAGE=page;
}
Buffer[ImageOffset++]=*(unsigned char far *)(DisplayAdd+O);
}
offset+=640;
}
}
void PutImage(long Left,long Top,long Right,long Bottom,char *Buffer)
{
int ImageOffset=0;
unsigned long offset,O,page;
long pixel;
long ImageHigh=Bottom-Top;
long ImageWidth=Right-Left;
offset=Left+(Top<<9)+(Top<<7);
for(Top=0;Top<=ImageHigh;Top++)
{
for(Left=0;Left<=ImageWidth;Left++)
{
pixel=offset+Left;
page=(pixel>>16);
O=pixel-(page<<16);
if(page!=CUR_PAGE)
{
SelectPage(page);
CUR_PAGE=page;
}
*(unsigned char far *)(DisplayAdd+O)=Buffer[ImageOffset++];
}
offset+=640;
}
}
void ShowAllColor(void)
{ int i,j,k;
for(i=0;i<100;i++)
{ SetColor(i);
Line(i*6,0,i*6,10);
Line(i*6+1,0,i*6+1,10);
Line(i*6+2,0,i*6+2,10);
/*/OutCharXY(i*6,12,i);*/
};
for(i=100;i<200;i++)
{ SetColor(i);
Line((i-100)*6,20,(i-100)*6,30);
Line((i-100)*6+1,20,(i-100)*6+1,30);
Line((i-100)*6+2,20,(i-100)*6+2,30);
/*/OutCharXY((i-100)*6,32,i-100);*/
};
for(i=200;i<256;i++)
{ SetColor(i);
Line((i-200)*6,40,(i-200)*6,50);
Line((i-200)*6+1,40,(i-200)*6+1,50);
Line((i-200)*6+2,40,(i-200)*6+2,50);
/*/OutCharXY((i-200)*6,52,i-200);*/
};
};
#endif /* __GRAPH_H */

这个库在优化方面不使很好,不过逻辑很简单。

Neo的优化就繁琐而变态了,我只取了其中画点和县的函数,改进前半部分:
/*****************************************************************************************
利用neo的底层函数结合我的.l文件,总算实现了一个速度够快,又够小的版本
2005/5/22
******************************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<conio.h>
//#include<neo.h>
#include<dos.h>
#include<io.h>
#include<time.h>
#include<fcntl.h>
/*图形驱动*/
/*NEO SDK For Turbo C 2.x/WIN-TC
Copyright Cker Home 2003-2005.

Open Source Obey NEO_PL.TXT.
http://neosdk.91i.net
ckerhome@yahoo.com.cn

文件名称 : n2d.h
摘 要 : 本头文件包含了NEO SDK里有关VESA底层操作的各种基本图形函数、结构、全局
变量的声明及定义
当前版本 : V4.14
作 者 : 董凯
完成日期 : 2005.1.10

取代版本 : 3.80
原 作 者 : 董凯
完成日期 : 2005.1.9
*/
#ifndef N2D_H
#define N2D_H

#if defined NEO_color_depth_16_unused && defined NEO_color_depth_8_unused
#undef NEO_color_depth_8_unused
#undef NEO_color_depth_16_unused
#endif

#ifndef NEO_draw_optimization_unused
#define NEO_draw_optimization_used 1
#else
#define NEO_draw_optimization_used 0
#endif

#if defined NEO_rect_unused
#define NEO_rect_used 1
#else
#define NEO_rect_used 0
#endif


#ifdef NEO_hi_graphics_h_used
#ifdef USER_CHAR_SIZE
#if VERT_DIR
#error Please don't include graphics.h!
#endif
#endif


#define closegraph() set_vbe_mode(0x3)
#define getgraphmode() get_vbe_mode()
#define setgraphmode(mode) set_vbe_mode(mode)
#define setviewport(l, t, r, b,c) screen(l, t, r, b):0
#define getmaxx() max_x()
#define getmaxy() max_y()
#define setwritemode(mode) set_draw_mode(mode)
#define setcolor(color) (g_frt_color = color)
#define setbkcolor(color) clear_to_color(color)
#define getcolor(color) g_frt_color
#define setrgbpalette(cn, r, g,b) set_color(cn, r, g, b)
#define putpixel(x, y, color) dot(x, y, color)
#define getpixel(x, y) get_dot(x, y)
#define bar(x0, y0, x1, y1) rectfill(x0-1, y0-1, x1-1, y1-1, g_frt_color)
#define rectangle(x0, y0, x1, y1) rect(x0, y0, x1, y1, g_frt_color)
#define textcolor(color) set_str_color(color)
#define outtextxy(x, y, str) textout(str, x, y)
#define textwidth() textheight()
#endif

#define _WHITE 0xf
#define _BLACK 0

#define max_x() g_screen_h
#define max_y() g_screen_v
#define get_color_depth() g_color_depth

#define VBE320X200X256 0X13
#define VBE640X400X256 0X100
#define VBE640X480X256 0X101
#define VBE800X600X256 0X103
#define VBE1024X768X256 0X105
#define VBE1280X1024X256 0X107

#define VBE320X200X32K 0X10D
#define VBE640X480X32K 0X110
#define VBE800X600X32K 0X113
#define VBE1024X768X32K 0X116
#define VBE1280X1024X32K 0X119

#define VBE320X200X64K 0X10E
#define VBE640X480X64K 0X111
#define VBE800X600X64K 0X114
#define VBE1024X768X64K 0X117
#define VBE1280X1024X64K 0X11A

#define SCREEN_W g_screen_h
#define SCREEN_H g_screen_v

/*#ifndef __VIDEO
enum COLORS
{
BLACK,
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHTGRAY,
DARKGRAY,
LIGHTBLUE,
LIGHTGREEN,
LIGHTCYAN,
LIGHTRED,
LIGHTMAGENTA,
YELLOW,
WHITE
};
#endif
*/
enum TPTCOLOR
{
TPT8,
TPT15 = 0X7C1F,
TPT16 = 0XF81F,
//TPT24 = 0XFF00FFL,
//TPT32 = 0XFF00FFL,
};

enum DRAWIMAGEOPS
{
COPY_PUT,
XOR_PUT,
OR_PUT,
AND_PUT,
NOT_PUT
};

typedef struct RGB
{
unsigned char r;
unsigned char g;
unsigned char b;
}RGB, *RGB_ptr;

typedef struct PIC_RGB
{
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
}PIC_RGB, *PIC_RGB_ptr;


typedef struct ModeInfoBlock
{
unsigned short mode_attributes; /* Mode attributes */
unsigned char win_a_attributes; /* Window A attributes */
unsigned char win_b_attributes; /* Window B attributes */
unsigned short win_granularity; /* Window granularity in k */
unsigned short win_size; /* Window size in k */
unsigned short win_a_segment; /* Window A segment */
unsigned short win_b_segment; /* Window B segment */
void (far *win_func_ptr)(void); /* Pointer to window function */
unsigned short bytes_per_scan_line; /* Bytes per scanline */
unsigned short x_resolution; /* Horizontal resolution */
unsigned short y_resolution; /* Vertical resolution */
unsigned char x_char_size; /* Character cell width */
unsigned char y_char_size; /* Character cell height */
unsigned char number_of_planes; /* Number of memory planes */
unsigned char bits_per_pixel; /* Bits per pixel */
unsigned char number_of_banks; /* Number of CGA style banks */
unsigned char memory_model; /* Memory model type */
unsigned char bank_size; /* Size of CGA style banks */
unsigned char number_of_image_pages; /* Number of images pages */
unsigned char res1; /* Reserved */
unsigned char red_mask_size; /* Size of direct color red mask */
unsigned char red_field_position; /* Bit posn of lsb of red mask */
unsigned char green_mask_size; /* Size of direct color green mask */
unsigned char green_field_position; /* Bit posn of lsb of green mask */
unsigned char blue_mask_size; /* Size of direct color blue mask */
unsigned char blue_field_position; /* Bit posn of lsb of blue mask */
unsigned char rsvd_mask_size; /* Size of direct color res mask */
unsigned char rsvd_field_position; /* Bit posn of lsb of res mask */
unsigned char direct_color_mode_info; /* Direct color mode attributes */
unsigned char res2[216]; /* Pad to 256 byte block size */
}mode_info_t;


#define PAL_SIZE 256
typedef RGB PALLETE[PAL_SIZE];
#define PALETTE PALLETE

/*------------------------NEO的私有全局变量(请勿擅自俢改,以免造成不可预料的错误!)---------------------*/
char far *g_videoptr = (char far *)0xa0000000;
char g_routines;
char g_page_num;
char g_green_mask = 0;
char g_green_bit = 0;
char g_color_depth = 0; /*记录当前图形模式的色深,为0表示非图形模式*/
int g_screen_h; /*当前分辨率下的屏幕宽度*/
int g_screen_v; /*当前分辨率下的屏幕高度*/
long g_screen_size; /*记录当前图形模式的屏幕面积*/
unsigned g_blit_fix; /*NEO目前用于blit()函数的临时变量*/
int g_cur_vbe_page = 0; /*当前所处的显示页*/
/*----------------------------------------------------------------------------------------------------*/
int g_frt_color = 1;
int g_tptcolor = 0; /*本开发包指定透明色(Transparent color)*/
char g_draw_mode = 0; /*绘图模式,分为COPY_PUT,XOR_PUT,OR_PUT,AND_PUT,NOT_PUT,与TC中Graphics的绘图模式意义相同*/
/*以下4个变量用来支持裁剪输出,分别代表裁剪区域的左上角及右下角坐标*/
int g_rect_left;
int g_rect_right;
int g_rect_top;
int g_rect_bottom;
char g_dac_size_fix = 2; /*记录DAC调色板宽度修正值,由8-当前DAC宽度得来,默认为2*/

/*======================================================*
* 函数声明(Function declare) *
*======================================================*/
char set_vbe_mode(int mode);
int get_vbe_mode();
char get_page_num();
char screen(unsigned left, unsigned top, unsigned right, unsigned bottom);
void set_vbe_page(char page);
#ifndef NEO_draw_mode_unused
void set_draw_mode(int draw_mode);
#endif
void set_neo_color();
void set_palette_range(char *pal_buf, int from, int to, int vsync_flag);
void get_palette_range(char *pal_buf, int from, int to);
char set_color(int index, char red,char green, char blue);
#ifndef NEO_palette_unused
void set_dac_size(unsigned char size);
char get_dac_size();
void set_palette(char *pal_buf);
void get_palette(char *pal_buf);
char get_red(int index);
char get_green(int index);
char get_blue(int index);
void fade_out(unsigned char dest_color, long timedelay);
#endif

void dot(int x,int y,int color);
int get_dot(int x, int y);
#ifndef NEO_basic_draw_unused
#ifndef NEO_hi_graphics_h_used
void line(int x1, int y1, int x2, int y2, unsigned color);
void circle(int c_x, int c_y, int r, unsigned char color);
void ellipse(int x0, int y0, int a, int b, unsigned char color);
#else
void line(int x1, int y1, int x2, int y2);
void circle(int c_x, int c_y, int r);
void ellipse(int x0, int y0, int a, int b);
#endif
char hline(int x, int y, int width, unsigned color);
void vline(int x, int y, int height,unsigned color);
void rect(int x0, int y0, int x1, int y1, int color);
void tri(int xa, int ya, int xb, int yb, int xc, int yc, int col);
void rectfill(int x1, int y1, int x2, int y2, int color);
void circlefill(int x, int y, int r, int c);
void _dot(int x,int y,int color);
#endif

void clear();
void clear_to_color(int color);
void vsync();

char g_en_slant = 0;
char g_cn_size = 1;
int g_str_color = 1;
int g_text_bg = -1;

extern void show_mouse();
extern void hide_mouse();

void vsync()
{
while ( inportb(0x3da)&0x08 ) ;
while (!(inportb(0x3da)&0x08)) ;
}


char neo_init()
{
atexit(0);
return 0;
}

/*获得ROM字符集首地址*/
unsigned char far *get_asc_rom(unsigned int bx)
{
struct REGPACK reg;
reg.r_ax = 0x1130;
reg.r_bx = bx;
intr(0x10, &reg);
return (unsigned char far*)MK_FP(reg.r_es, reg.r_bp);
}


/*选择要使用的ASCII ROM字符集*/
unsigned char far *cur_asc_rom(int *chose)
{
static char fault_ch = 8;
static unsigned char far *romaddr = (unsigned char far *)0xf000fa6e;

if (*chose>0)
{
switch (fault_ch = *chose)
{
case 8 : /*获得8*8 ASCII ROM字符集首地址*/
return romaddr = get_asc_rom(0x0300);
case 14: /*获得14*8 ASCII ROM字符集首地址*/
return romaddr = get_asc_rom(0x0200);

case 16: /*获得16*8 ASCII ROM字符集首地址*/
return romaddr = get_asc_rom(0x0600);

default:
romaddr = get_asc_rom(0x0300);
*chose = fault_ch = 8;
return romaddr;
}
}
*chose = fault_ch;
return romaddr;
}

/*======================================================*
* 函数定义(Function definitions) *
*======================================================*/
/*設置SVGA的显示模式*/
char set_vbe_mode(int mode)
{
mode_info_t mode_info;
struct SREGS segs;
union REGS r;
char far *modeinfo = (char far *)&mode_info;

r.x.ax = 0x4f02;
r.x.bx = mode;
int86(0x10, &r, &r);

if (mode < 0x100)
{
if (mode == 0x13)
{
g_color_depth = 8;
g_rect_left = g_rect_top = 0;
g_rect_right = (g_screen_h = 320) - 1;
g_rect_bottom = (g_screen_v = 200) - 1;
g_screen_size = g_screen_h * g_screen_v;
g_tptcolor = TPT8;
screen(0, 0, g_rect_right, g_rect_bottom);
return 1;
}
else
return 0; /* Ignore non-VBE modes */
}
else
{
r.x.ax = 0x4f01;
r.x.cx = mode;
r.x.di = FP_OFF(modeinfo);
segs.es = FP_SEG(modeinfo);
int86x(0x10, &r, &r, &segs);
if (r.x.ax != 0x4F) return 0;
}

#ifndef NEO_bmp_masked_blit_unused
switch (mode) /*临时使用*/
{
case 0x101:
g_blit_fix = 45056;
break;
case 0x103:
g_blit_fix = 21248;
break;
case 0x105:
g_blit_fix = 65534;
break;
default:
g_blit_fix = 0;
break;
}
#endif

g_green_mask = mode_info.green_mask_size;
g_color_depth = mode_info.bits_per_pixel;
g_rect_left = g_rect_top = 0;
g_rect_right = (g_screen_h = mode_info.x_resolution) - 1;
g_rect_bottom = (g_screen_v = mode_info.y_resolution) - 1;
g_screen_size = g_screen_h * g_screen_v;
screen(0, 0, g_rect_right, g_rect_bottom);

switch (g_color_depth)
{
case 8:
g_tptcolor = TPT8;
break;
case 15:
g_tptcolor = TPT15;
g_green_bit= 3;
break;
case 16:
g_tptcolor = TPT16;
g_green_bit= 2;
break;
case 24:
//g_tptcolor = TPT24;
break;
case 32:
//g_tptcolor = TPT32;
break;
default:
g_tptcolor = TPT8;
break;
}

g_routines |= 1;
g_page_num = get_page_num();
return 1;
}


/*获得SVGA的显示模式*/
int get_vbe_mode(void)
{
_AX = 0x4f03;
__int__(0x10);

return _BX;
}

char get_page_num()
{
char pages[28] = {4, 5, 4, 8, 6, 12, 10, 20, -1, -1, -1, -1, -1, 2, 2, 3, 10, 10, 15,
15, 15, 22, 24, 24, 36, 40, 40, 60};
int tmp;
_AX = 0x4f03;
__int__(0x10);

if ((tmp = _BX) >= 0x100)
{
return pages[tmp - 256];
}
else if (tmp == 0x13)
{
return 1;
}
return -1;
}

/*指定剪切输出域(包括边线)*/
char screen(unsigned left, unsigned top, unsigned right, unsigned bottom)
{ g_rect_top=top;
g_rect_left = left;// = g_rect_top = top = 0;
g_rect_right = right;//= g_screen_h - 1;
g_rect_bottom= bottom;//=g_screen_v - 1;

return 0;
}


/*显存换页函数*/
void set_vbe_page(char page)
{
union REGS r;
if (g_cur_vbe_page != page)
{
r.x.ax=0x4f05;
r.x.bx=0;
r.x.dx=g_cur_vbe_page = page;
int86(0x10, &r, &r);
}
}


#ifndef NEO_draw_mode_unused
void set_draw_mode(int draw_mode)
{

(draw_mode>=COPY_PUT)&&(draw_mode<=NOT_PUT)?g_draw_mode=draw_mode : 0;
}
#endif


/*---------------------------------------------------*
*函数功能: 将硬件调色板转换为本SDK推荐的逻辑调色板. *
*参数说明: 无. *
*返回说明: 无.    *
*备 注: 本SDK推荐的调色板是由经典游戏"仙剑奇侠传"*
* 的调色板经过分类排序等修改而来的,选色专业*
* ,颜色齐,覆盖性好;一般匹配其他图片可以达到*
* 90%以上的近似效果.所以本SDK将其定为推荐调*
* 色盘.用户程序可直接调用.   *
*---------------------------------------------------*/
void set_neo_color()
{
#ifndef NEO_sys_pal_unused
unsigned char rgb[256][3] = {
0,0,0,6,6,6,10,10,10,14,14,14,18,18,18,22,22,22,26,26,26,30,30,30,34,34,34,38,38,38,42,42,42,
46,46,46,50,50,50,54,54,54,59,59,59,63,63,63,20,0,0,23,0,0,28,0,0,33,1,1,38,2,2,47,4,3,54,6,
5,63,0,0,63,0,0,63,14,11,63,18,15,63,22,19,63,22,18,63,32,28,63,37,33,63,43,39,18,5,2,21,6,3,
24,6,3,27,6,3,31,10,4,36,15,7,40,20,9,44,25,11,48,30,15,53,36,18,56,41,21,60,46,24,63,50,28,
63,55,33,63,60,39,63,62,44,12,6,0,22,15,0,32,25,0,41,34,1,48,43,1,57,50,1,59,56,1,62,62,1,62,
62,21,63,63,0,63,63,10,63,63,19,63,63,28,63,63,41,63,63,49,63,63,60,5,3,2,7,5,3,10,7,5,13,10,
7,16,13,9,18,16,11,21,19,14,24,22,16,27,25,19,29,28,21,32,31,24,35,34,28,38,37,31,41,40,36,
45,44,40,49,46,43,0,0,15,0,0,19,1,1,27,2,2,32,3,3,37,2,2,41,3,3,46,0,3,51,0,0,58,0,0,63,7,7,
63,14,14,63,21,21,63,28,28,63,38,38,63,42,42,63,7,4,14,9,5,17,11,6,20,13,8,23,15,10,26,18,12,
29,21,14,32,24,17,35,27,20,38,31,23,41,34,27,44,38,31,47,42,35,50,46,40,53,50,44,56,54,49,59,
5,9,10,7,11,13,9,14,16,11,17,19,13,20,22,16,23,25,19,26,28,22,30,32,26,33,35,30,37,39,33,40,
42,38,44,46,42,48,50,47,52,53,52,56,57,57,60,61,0,4,2,0,8,5,0,11,8,1,15,11,2,19,15,4,23,19,6,
26,22,8,30,26,11,34,29,13,38,33,17,42,37,21,46,41,26,50,45,31,54,49,36,58,52,42,62,57,23,10,
6,28,14,8,33,18,10,36,23,13,40,28,16,43,32,19,45,33,21,47,33,24,49,33,27,50,36,30,52,39,33,
54,42,37,55,45,40,57,48,43,58,51,47,60,54,50,12,4,0,16,6,0,21,8,1,24,10,2,27,12,3,30,15,6,33,
18,8,36,21,11,39,25,14,42,29,17,45,33,21,48,37,25,51,41,30,55,46,35,59,50,41,63,56,48,9,3,1,
12,5,2,15,7,3,18,9,4,22,13,7,25,16,9,28,19,12,32,23,15,35,28,18,39,32,22,42,36,27,46,41,31,
49,45,36,53,50,42,57,55,48,61,60,55,0,7,0,0,9,0,1,12,0,2,15,1,4,19,2,6,24,3,8,31,5,11,39,7,
14,45,9,0,49,0,6,49,0,11,49,0,19,49,19,26,49,22,32,49,26,28,49,31,0,6,23,0,8,27,1,10,31,3,12,
35,5,15,40,7,17,44,10,20,48,13,23,50,17,27,52,21,31,55,25,35,56,30,39,58,35,43,59,39,47,60,
44,51,61,50,55,63,9,5,3,12,7,4,15,10,6,18,13,8,22,17,11,25,20,13,28,23,16,31,27,19,34,30,22,
37,34,26,40,37,30,44,41,34,47,45,38,50,49,42,53,52,46,56,55,50, 0,0,0,32,0,0,0,32,0,32,32,
0,0,0,32,32,0,32,0,32,32,32,32,32,48,48,48,63,0,0,0,63,0,63,63,0,0,0,63,63,0,63,0,63,
63,63,63,63
};
set_palette(*rgb);
#endif
}


void set_palette_range(char *pal_buf, int from, int to, int vsync_flag)
{
struct REGPACK reg;
if (from <= to && from >= 0 && from < 256 && to - from < 256)
{
if (vsync_flag)
vsync();
reg.r_ax = 0x1012;
reg.r_bx = from;
reg.r_cx = to - from + 1;
reg.r_es = FP_SEG(pal_buf);
reg.r_dx = FP_OFF(pal_buf);
intr(0x10,&reg);
}
}


void get_palette_range(char *pal_buf, int from, int to)
{
struct REGPACK regs;
if (from <= to && from >= 0 && from < 256 && to - from < 256)
{
regs.r_ax = 0x1017;
regs.r_bx = from;
regs.r_cx = to - from + 1;
regs.r_es = FP_SEG(pal_buf);
regs.r_dx = FP_OFF(pal_buf);
intr(0x10,&regs);
}
}


/*---------------------------------------------------*
*函数功能: 设置硬件调色板中指定颜色号的颜色分量. *
*参数说明: index为颜色号. *
* red,green,blue为此颜色号对应的红,绿,兰三 *
* 原色分量,均应小于64) *
*返回说明: 成功返回1;否则返回0. *
*备 注: 颜色设置函数.用户程序可直接调用.   *
*---------------------------------------------------*/
char set_color(int index, char red,char green, char blue)
{
unsigned char color[3];

color[0] = red;
color[1] = green;
color[2] = blue;
set_palette_range(color, index, index, 0);
return -1;
}


#ifndef NEO_palette_unused
/*---------------------------------------------------*
*函数功能: 设置硬件调色板为逻辑调色板. *
*参数说明: pal_buf指向存放256种颜色分量数组的指针. *
*这个数组的形式一般可以有两种:pal[256][3]和pal[768]*
*返回说明: 无. *
*备 注: 颜色设置函数.用户程序可直接调用.   *
*---------------------------------------------------*/
void set_palette(char *pal_buf)
{
#ifndef NEO_draw_smooth_unused
set_palette_range(pal_buf, 0, 255, 1);
#else
set_palette_range(pal_buf, 0, 255, 0);
#endif
}

void get_palette(char *pal_buf)/*获取系统调色板*/
{
get_palette_range(pal_buf, 0, 255);
}


char get_red(int index)
{
unsigned char color[3];

get_palette_range(color, index, index);
return color[0];
}

char get_green(int index)
{
unsigned char color[3];

get_palette_range(color, index, index);
return color[1];
}

char get_blue(int index)
{
unsigned char color[3];

get_palette_range(color, index, index);
return color[2];
}


void set_dac_size(unsigned char size)
{
_AX = 0x4f08;
_BL = 0;
_BH = size;
__int__(0x10);
g_dac_size_fix = ((size == 6) || (size == 8)) ? 8 - size : 2;
}

char get_dac_size()
{
_AX = 0x4f08;
_BL = 1;
__int__(0x10);
g_dac_size_fix = 8 - _BH;
return 8 - g_dac_size_fix;
}


void fade_out(unsigned char dest_color, long timedelay)
{
#ifndef NEO_color_depth_8_unused
unsigned int i, j;
unsigned char dac[256][3];
unsigned char rgb[3];

rgb[0] = get_red(dest_color);
rgb[1] = get_green(dest_color);
rgb[2] = get_blue(dest_color);

get_palette(*dac);
for (j = 0; j < 64; ++j)
{
for (i = 0; i<256; ++i)
{
dac[i][0] > rgb[0]?dac[i][0]--:dac[i][0]++;
dac[i][1] > rgb[1]?dac[i][1]--:dac[i][1]++;
dac[i][2] > rgb[2]?dac[i][2]--:dac[i][2]++;
}
set_palette(*dac);
delay(timedelay);
}
#else
dest_color += 0;
timedelay += 0;
#endif
}

#endif


/*通用画点函数,速度:17FPS*/
void dot(int x,int y,int color)
{
long addr;
int page;
if ((x<g_rect_left) || (y<g_rect_top) || (x>g_rect_right) || (y>g_rect_bottom)) return;

if (g_color_depth == 8)
{
#ifndef NEO_color_depth_8_unused
page = (int)((addr = (long)y * g_screen_h + x) >> 16);

if (g_cur_vbe_page != page)
{
_BX = 0;
_DX = g_cur_vbe_page = page;
_AX = 0x4f05;
__int__(0x10);
}
#ifndef NEO_draw_mode_unused
switch(g_draw_mode)
{
case COPY_PUT : *(g_videoptr+(addr&0xffff)) = color;break;
case XOR_PUT : *(g_videoptr+(addr&0xffff))= *(g_videoptr+(addr& 0xffff))^(char)color;break;
case NOT_PUT : *(g_videoptr+(addr&0xffff))=~*(g_videoptr+(addr& 0xffff));break;
case OR_PUT : *(g_videoptr+(addr&0xffff))= *(g_videoptr+(addr& 0xffff))|(char)color;break;
case AND_PUT : *(g_videoptr+(addr&0xffff))= *(g_videoptr+(addr& 0xffff))&(char)color;break;
}
#else
*(g_videoptr+(addr& 0xffff)) = (unsigned char)color;
#endif

#else
x += 0; y+=0; color+=0;
#endif
}
else /*if (g_color_depth == 16)*/ /*由于NEO 1.1.00只支持256和64K色,所以暂时注释左边一句*/
{
#ifndef NEO_color_depth_16_unused
int far *videoptr16 = (int far *)0xa0000000;
page = (int)((addr = (long)y * g_screen_h + x) >> 15);

if (g_cur_vbe_page != page)
{
_BX = 0;
_DX = g_cur_vbe_page = page;
_AX = 0x4f05;
__int__(0x10);
}
#ifndef NEO_draw_mode_unused
switch(g_draw_mode)
{
case COPY_PUT : *(videoptr16+(addr&0xffff)) = color;break;
case XOR_PUT : *(videoptr16+(addr&0xffff))= *(videoptr16+(addr& 0xffff)) ^ color;break;
case NOT_PUT : *(videoptr16+(addr&0xffff))=~*(videoptr16+(addr& 0xffff)); break;
case OR_PUT : *(videoptr16+(addr&0xffff))= *(videoptr16+(addr& 0xffff)) | color;break;
case AND_PUT : *(videoptr16+(addr&0xffff))= *(videoptr16+(addr& 0xffff)) & color;break;
}
#else
*(videoptr16 + (addr & 0xffff)) = color;
#endif

#else
x += 0; y+=0; color+=0;
#endif
}
}
void putpixel(int x,int y,int color)
{dot(x,y,color);
}

int get_dot(int x, int y)
{
/*union REGS r;*/
long addr;
int page;
if ((x<0) || (y<0) || (x>g_screen_h) || (y>g_screen_v)) return -1;

if (g_color_depth == 8)
{
#ifndef NEO_color_depth_8_unused
page = (int)((addr = (long)y * g_screen_h + x) >> 16);
if (g_cur_vbe_page != page)
{
_BX = 0;
_DX = g_cur_vbe_page = page;
_AX = 0x4f05;
__int__(0x10);
}
return (peekb(0xa000,addr & 0xFFFF));
#else
x += 0; y+=0;
#endif
}
else
{
#ifndef NEO_color_depth_16_unused
int far *videoptr = (int far *)0xa0000000;
page = (int)((addr = (long)y * g_screen_h + x) >> 15);

if (g_cur_vbe_page != page)
{
_BX = 0;
_DX = g_cur_vbe_page = page;
_AX = 0x4f05;
__int__(0x10);
}
return *(videoptr + (addr & 0xffff));
#else
x += 0; y+=0;
#endif
}
}

int getpixel(int x,int y)
{return get_dot(x,y);
}

#ifndef NEO_basic_draw_unused

#ifndef NEO_hi_graphics_h_used
/*通用的画线函数,用color颜色由(x1,y1)画到(x2,y2);速度:(16FPS)*/
void line(int x1, int y1, int x2, int y2, unsigned color)
{
int dt_x = x2 - x1, dt_y = y2 - y1, step_x, step_y, change;

if (dt_x < 0)
{
dt_x = -dt_x; /*从右向左画线*/
step_x = -1;
}
else {step_x = 1;} /*从左向右画线*/

if (dt_y < 0)
{
dt_y = -dt_y; /*从下向上画线*/
step_y = -1;
}
else {step_y = 1;}
/*从上向下画线*/
if (dt_x > dt_y) /*x改变得比y快*/
{
change = dt_x >> 1;
while (x1 != x2)
{
dot(x1, y1, color);
x1 += step_x;
change += dt_y;
if(change > dt_x)
{
y1 += step_y;
change -= dt_x;
}
}
}
else /*y改变得比x快*/
{
change = dt_y >> 1;
while(y1 != y2)
{
dot(x1, y1, color);
y1 += step_y;
change += dt_x;
if(change > dt_y)
{
x1 += step_x;
change -= dt_y;
}
}
}
dot(x2, y2, color);
}
#else
void line(int x1, int y1, int x2, int y2)
{
int dt_x = x2 - x1, dt_y = y2 - y1, step_x, step_y, change;

if (dt_x < 0)
{
dt_x = -dt_x; /*从右向左画线*/
step_x = -1;
}
else {step_x = 1;} /*从左向右画线*/

if (dt_y < 0)
{
dt_y = -dt_y; /*从下向上画线*/
step_y = -1;
}
else {step_y = 1;}
/*从上向下画线*/
if (dt_x > dt_y) /*x改变得比y快*/
{
change = dt_x >> 1;
while (x1 != x2)
{
dot(x1, y1, g_frt_color);
x1 += step_x;
change += dt_y;
if(change > dt_x)
{
y1 += step_y;
change -= dt_x;
}
}
}
else /*y改变得比x快*/
{
change = dt_y >> 1;
while(y1 != y2)
{
dot(x1, y1, g_frt_color);
y1 += step_y;
change += dt_x;
if(change > dt_y)
{
x1 += step_x;
change -= dt_y;
}
}
}
dot(x2, y2, g_frt_color);
}
#endif

/*优化后的画水平线函数,用color颜色由(x,y)向右画长为width的水平线;速度: 8位65FPS; 16位32FPS*/
char hline(int x, int y, int width, unsigned color)
{
long addr;
int k = 0;
int xx = x;
int rect_scr_h = g_rect_right + 1;
int len = 0, length/*直线有效长度*/ = 0;
char page, odd;

if (width < 0)
{
x -= width;
width = -width;
}
if (g_color_depth == 8)
{
#ifndef NEO_color_depth_8_unused
int origin = 0;
unsigned char color8 = (unsigned char)color;
unsigned int color16 = color8 << 8;

if ( (y > g_rect_bottom) || (y < g_rect_top) || width < 0)
{
return -1;
}
if (x >= 0 && x < rect_scr_h)
{
if (rect_scr_h - x >= width) /*直线完全显示*/
{
len = length = width + 1;
}
else /*直线右边溢出*/
{
len = length = rect_scr_h - x + 1;
}
}
else if (x < 0 && x > (-width))
{
if (width + x >= rect_scr_h) /*直线两端溢出*/
{
len = length = rect_scr_h + 1;
xx = x = 0;
}
else /*直线左边溢出*/
{
len = (length = width + 1) + x;
x = 0;
}
}
else
{
return -1;
}

color16 += color8;
len >>= 1;
length -= (odd = length % 2);
origin = (g_rect_left) >> 1;

page = (char)((addr = (long)(y) * g_screen_h + x) >> 16);
if (page == (addr + length) >> 16)
{
int far *d_tmp = (int far *)(g_videoptr + (addr & 0xffff));

if (g_cur_vbe_page != page)
{
set_vbe_page(page);
}
for (; origin < len; ++origin)
{
#ifndef NEO_draw_mode_unused
switch(g_draw_mode)
{
case COPY_PUT : d_tmp[origin] = color16; break;
case XOR_PUT : d_tmp[origin] = d_tmp[origin] ^ color16; break;
case NOT_PUT : d_tmp[origin] = ~d_tmp[origin]; break;
case OR_PUT : d_tmp[origin] = d_tmp[origin] | color16; break;
case AND_PUT : d_tmp[origin] = d_tmp[origin] & color16; break;
}
#else
d_tmp[origin] = color16;
#endif
}
}
else
{
for (;k </*=*/ length; ++k)
dot(k + xx, y,color8);
}
if (odd) dot(xx + length, y, color8);
#else
x += 0; y += 0; width += 0; color += 0;
#endif
return 0;
}
else
{
#ifndef NEO_color_depth_16_unused
if ( (y > g_rect_bottom) || (y < g_rect_top) || width < 0)
{
return -1;
}
if (x >= 0 && x < rect_scr_h)
{
if (rect_scr_h - x >= width) /*直线完全显示*/
{
len = length = width + 1;
}
else /*直线右边溢出*/
{
len = length = rect_scr_h - x + 1;
}
}
else if (x < 0 && x > (-width))
{
if (width + x >= rect_scr_h) /*直线两端溢出*/
{
len = length = rect_scr_h + 1;
xx = x = 0;
}
else /*直线左边溢出*/
{
len = (length = width + 1) + x;
x = 0;
}
}
else
{
return -1;
}

page = (char)((addr = (long)(y) * g_screen_h + x) >> 15);
if (page == (addr + length) >> 15)
{
int far *d_tmp = (int far *)(g_videoptr + ((addr<<1) & 0xffff));

if (g_cur_vbe_page != page)
{
set_vbe_page(page);
}
for (k = g_rect_left; k < len; ++k)
{
#ifndef NEO_draw_mode_unused
switch(g_draw_mode)
{
case COPY_PUT : d_tmp[k] = color; break;
case XOR_PUT : d_tmp[k] = d_tmp[k] ^ color; break;
case NOT_PUT : d_tmp[k] = ~d_tmp[k]; break;
case OR_PUT : d_tmp[k] = d_tmp[k] | color; break;
case AND_PUT : d_tmp[k] = d_tmp[k] & color; break;
}
#else
d_tmp[k] = color;
#endif
}
}
else
{
for (k = g_rect_left;k < length; ++k)
dot(k + xx, y, color);
}
#else
x += 0; y += 0; width += 0; color += 0;
#endif
return 0;
}
}
#endif
#endif

void rectfill(int x1, int y1, int x2, int y2, int color)
{
int delta, temp;

if (x1 > x2)
{
temp = x1; x1 = x2; x2 = temp;
}
if (y1 > y2)
{
temp = y1; y1 = y2; y2 = temp;
}
delta = x2 - x1;
for (temp=y1; temp<=y2; ++temp)
{
hline(x1, temp, delta, color);
}
}

void bar(int x1, int y1, int x2, int y2, int color)
{rectfill(x1,y1,x2,y2,color);
}


/*显示单个English字符*/
void en_out(char c, int cx, int cy)
{
int i, x, y, num = 0;
unsigned char bit = 1;
char slant = 0;
int ascrom[1] = {-1};
char far *romchar_p = cur_asc_rom(ascrom);
char far *temp_p;
temp_p = romchar_p + c * (*ascrom);

for (y = 0; y < *ascrom; ++y)
{
bit = 1;slant += g_en_slant;
for (x = 0; x < 8; ++x)
{
num = bit & (*temp_p);
num >>= x;
if (num == 1)
{
dot(cx + 8 - x+slant, cy + y, g_str_color);
}
else if (g_text_bg >= 0)
{
dot(cx + 8 - x+slant, cy + y, g_text_bg);
}
bit <<= 1;
}
++temp_p;
}
}


/*显示English字符串*/
void outtextxy(int sx, int sy,char *str)
{
int index;
for (index = 0; str[index] != 0; index++)
{
en_out(str[index], sx + (index << 3), sy);
}
}


/*图形驱动*/

neo是256色的驱动,好在和16色的绘图函数是兼容的,图形库的创始人真是聪明极了。

还有个问题一直没理解,一直认为neo画点速度快就是因为换页时计算了一下所以比原来的库函数快些,自己写了最简单的256色函数,加上换页等等,还是比neo慢一些,见了鬼了。不过做好了一个又快又小的版本,目的已经达到了,不再深究了,睡觉最要紧。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值