三、代码实现
本实例程序用Turbo C 2.0在Large模式下编译通过。程序用绿色生成曲面z=sin(x*y),x [-3,3],y [-3,3]的真实感图形,并将其写入BMP格式的文件。笔者作过比较,在同等条件下,按照文中开始陈述的方法在WINDOWS下显示曲面的真实感图形需8秒,而应用扩展内存技术实现曲面真实感图形的生成和显示只需1.5秒,效果相当不错。由于采用文件存放图形数据,所以很容易实现DOS和WINDOWS下的快速显示。限于篇幅,本文略出快速显示BMP文件的部分,读者可以用WIN95的画图在真彩色下显示。
/*xms.h*/
#include<dos.h>
#include<conio.h>
union address {
unsigned int part[2];
long offset;
};
struct emm {
long length;
unsigned int source_handle;
union address source;
unsigned int target_handle;
union address target;
};
void far(* _p)( );
char xms_installed( )
{
_AX=0x4300;
geninterrupt(0x2f);
if(_AL!=0x80) {
textmode(3);
printf("XMS is not installed\n!");
exit(1);
}
return(_AL);
}
void xms_entry( )
{
_AX=0x4310;
geninterrupt(0x2f);
_p=MK_FP(_ES,_BX);
return;
}
void test_xms(unsigned int size)
{
_AH=8; _p( );
if(_AX<size) {
textmode(3);
printf("No enough XMS to be used!\n");
exit(1);
}
}
unsigned int alloc_xms(unsigned int size)
{
_DX=size; _AH=9;
_p( );
if(_AX!=1) {
textmode(3);
printf("XMS allocation is error\n");
exit(1);
}
return(_DX);
}
void move_xms(struct emm *xms)
{
_DS=FP_SEG(xms);
_SI=FP_OFF(xms);
_AH=0x0b; _p( );
if(_AX!=1) {
textmode(3);
printf("XMS move error! %d\n",_BL);
exit(1);
}
return;
}
void free_xms(unsigned int handle)
{
_DX=handle; _AH=0x0a;
_p( );
}
/*surface.c*/
#include<stdio.h>
#include<dos.h>
#include<math.h>
#include<alloc.h>
#include<mem.h>
#include<conio.h>
#include<stdlib.h>
#include<xms.h>
#define PI 3.1415927
int ox,oy,length,width,height,N;
float sita,gama,dx,dy,deltax,deltay;
float xmin,xmax,ymin,ymax,zmin,zmax;
int v[5][2],vx[100][4],num[100],vymin,vymax;
struct emm xms;
unsigned int handle;
int WIDTH,HEIGHT;
int left,top,right,bottom,byteperpixel;
struct{
unsigned char type[2];
long size;
long reserved;
long offset;
}head;
struct{
long size;
long width;
long height;
int plane;
int bitcount;
long compression;
long imagesize;
long xpels;
long ypels;
long colorused;
long colorimportant;
}bmp;
void xmsinitial(int size)
{
xms_installed( );
xms_entry( );
test_xms(size);
handle=alloc_xms(size);
}
void putpixel(long x,long y,unsigned char red,
unsigned char green,unsigned char blue)
{
unsigned char *pixel;
pixel=malloc(byteperpixel*
sizeof(unsigned char));
pixel[0]=blue; pixel[1]=green;
pixel[2]=red; pixel[3]=0;
xms.target.offset=byteperpixel*(WIDTH*y+x);
xms.length=byteperpixel;
xms.source_handle=0;
xms.source.part[0]=FP_OFF(pixel);
xms.source.part[1]=FP_SEG(pixel);
xms.target_handle=handle;
move_xms(&xms);
free(pixel);
}
void level(long left,long right,long y,
unsigned char red,unsigned char green,
unsigned char blue)
{
long i;
unsigned char *pixel;
pixel=malloc(byteperpixel*(right-
left+1)*sizeof(unsigned char));
for(i=0;i<=right-left;i++) {
pixel[4*i]=blue;
pixel[4*i+1]=green;
pixel[4*i+2]=red;
} xms.target.offset=byteperpixel*(WIDTH*y+left);
xms.length=byteperpixel*((right-left+1));
xms.source_handle=0;
xms.source.part[0]=FP_OFF(pixel);
xms.source.part[1]=FP_SEG(pixel);
xms.target_handle=handle;
move_xms(&xms);
free(pixel);
}
void line(int x1,int y1,int x2,int y2,
unsigned char red,unsigned char green,
unsigned char blue)
{
int e,i,x,y,dx,dy,incx,incy;
x=x1;y=y1;
dx=abs(x2-x1);dy=abs(y2-y1);
if(x1<=x2) incx=1;
else incx=-1;
if(y1<=y2) incy=1;
else incy=-1;
if(dx>dy) {
e=2*dy-dx;
for(i=0;i<=dx;i++) {
putpixel(x,y,red,green,blue);
x=x+incx;
if(e>=0) e=e+2*dy-2*dx;
else e=e+2*dy;
if(e>=0) y=y+incy;
}
}
else {
e=2*dx-dy;
for(i=0;i<=dy;i++) {
putpixel(x,y,red,green,blue);
y=y+incy;
if(e>=0) e=e+2*dx-2*dy;
else e=e+2*dx;
if(e>=0) x=x+incx;
}
}
}
void rectangle(int left,int top,int right,int bottom,
unsigned char red,unsigned char green,
unsigned char blue)
{
level(left,right,top,red,green,blue);
line(right,top,right,bottom,red,green,blue);
level(left,right,bottom,red,green,blue);
line(left,bottom,left,top,red,green,blue);
}
void bar(int left,int top,int right,int bottom,
unsigned char red,unsigned char green,
unsigned char blue)
{
int y;
for(y=top;y<=bottom;y++)
level(left,right,y,red,green,blue);
}
void cleardevice(unsigned char red,
unsigned char green,unsigned char blue)
{
bar(0,0,WIDTH-1,HEIGHT-1,red,green,blue);
}
void dashedline(int x1,int y1,int x2,int y2,
unsigned char red,unsigned char green,
unsigned char blue)
{
int e,i,x,y,dx,dy,incx,incy;
x=x1;y=y1;
dx=abs(x2-x1);dy=abs(y2-y1);
if(x1<=x2) incx=1;
else incx=-1;
if(y1<=y2) incy=1;
else incy=-1;
if(dx>dy) {
e=2*dy-dx;
for(i=0;i<=dx;i++) {
if(4*(i/4)!=i)
putpixel(x,y,red,green,blue);
x=x+incx;
if(e>=0) e=e+2*dy-2*dx;
else e=e+2*dy;
if(e>=0) y=y+incy;
}
}
else {
e=2*dx-dy;
for(i=0;i<=dy;i++) {
if(4*(i/4)!=i)
putpixel(x,y,red,green,blue);
y=y+incy;
if(e>=0) e=e+2*dx-2*dy;
else e=e+2*dx;
if(e>=0) x=x+incx;
}
}
}
float f(float x0,float y0)
{
return(sin(x0*y0));
}
void getvertex(int i,int j,int s)
{
float x,y;
x=xmin+(xmax-xmin)*i/N;
y=ymin+(ymax-ymin)*j/N;
v[s][0]=ox+dx*j+deltax*i;
v[s][1]=oy-dy*j+deltay*i-
height*(f(x,y)-zmin)/(zmax-zmin);
}
void vertex(int x1,int y1,int x2,int y2)
{
int e,i,x,y,dx,dy,incx,incy,k;
if(y1>y2){
x=x1;y=y1;x1=x2;y1=y2;x2=x;y2=y;
}
x=x1;y=y1;
dx=abs(x2-x1);dy=abs(y2-y1);
if(x1<=x2) incx=1;
else incx=-1;
if(y1<=y2) incy=1;
else incy=-1;
if(dx>dy) {
e=2*dy-dx;
for(i=0;i<dx;i++) {
if(e>=0) {
k=num[y];vx[y][k]=x;num[y]++;
e=e+2*dy-2*dx;x=x+incx;y=y+incy;
}
else {
x=x+incx; e=e+2*dy;
}
}
}
else {
e=2*dx-dy;
for(i=0;i<dy;i++) {
k=num[y]; vx[y][k]=x;
num[y]++; y=y+incy;
if(e>=0){
e=e+2*dx-2*dy;x=x+incx;
}
else e=e+2*dx;
}
}
}
void drawline(int y,unsigned char red,
unsigned char green, unsigned char blue)
{
int i,x1,x2,x3,x4;
switch(num[y]) {
case 1:
putpixel(vx[y][0],y+vymin,red,green,blue);
break;
case 2:
x1=vx[y][0];x2=vx[y][1];
vx[y][0]=min(x1,x2);vx[y][1]=max(x1,x2);
level(vx[y][0],vx[y][1],y+vymin,red,green,blue);
break;
case 3:
for(i=0;i<4;i++)
if(v[i][1]==y+vymin){
vx[y][3]=v[i][0];break;
}
case 4:
x1=min(vx[y][0],vx[y][1]);
x2=max(vx[y][0],vx[y][1]);
x3=min(vx[y][2],vx[y][3]);
x4=max(vx[y][2],vx[y][3]);
vx[y][0]=min(x1,x3);vx[y][3]=max(x2,x4);
vx[y][1]=min(max(x1,x3),min(x2,x4));
vx[y][2]=max(max(x1,x3),min(x2,x4));
level(vx[y][0],vx[y][1],y+vymin,red,green,blue);
level(vx[y][2],vx[y][3],y+vymin,red,green,blue);
}
}
void fill(unsigned char red,
unsigned char green,unsigned char blue)
{
int i,y;
for(i=0;i<=vymax-vymin;i++)
num[i]=0;
for(i=0;i<4;i++)
vertex(v[i][0],v[i][1]-vymin,v[i+1][0],
v[i+1][1]-vymin);
for(y=0;y<(vymax-vymin);y++)
drawline(y,red,green,blue);
}
void draw3d( )
{
int i,j,k;
float x,y;
unsigned char red=0,green=0,blue=0;
dx=width*sin(gama)/N;
dy=width*cos(gama)/N;
deltax=length*cos(sita)/N;
deltay=length*sin(sita)/N;
for(j=N-1;j>=0;j--){
y=ymin+(ymax-ymin)*(j+0.5)/N;
getvertex(N,j,1);
getvertex(N,j+1,2);
for(i=N-1;i>=0;i--) {
x=xmin+(xmax-xmin)*(i+0.5)/N;
green=192+63*f(x,y);
getvertex(i,j,0);
getvertex(i,j+1,3);
vymin=v[0][1];vymax=v[0][1];
for(k=1;k<4;k++) {
if(vymin>v[k][1])
vymin=v[k][1];
if(vymax<v[k][1])
vymax=v[k][1];
}
v[4][0]=v[0][0];v[4][1]=v[0][1];
fill(red,green,blue);
v[1][0]=v[0][0];v[1][1]=v[0][1];
v[2][0]=v[3][0];v[2][1]=v[3][1];
}
}
}
void surface( )
{
int i,j,k,vx[8],vy[8],dashed[3]={0,2,7};
int solid[12]={0,1,2,6,5,1,5,4,0,4,7,6};
ox=100;oy=320;length=280;
width=180;height=80;
xmin=-3;xmax=3;ymin=-3;ymax=3;
zmin=-1;zmax=1;N=199;
sita=PI/12;gama=PI/4;
vx[0]=ox;vy[0]=oy;
vx[1]=ox+length*cos(sita);
vy[1]=oy+length*sin(sita);
vx[2]=vx[1]+width*sin(gama);
vy[2]=vy[1]-width*cos(gama);
vx[3]=ox+width*sin(gama);
vy[3]=oy-width*cos(gama);
vx[4]=vx[0];vy[4]=vy[0]-height;
vx[5]=vx[1];vy[5]=vy[1]-height;
vx[6]=vx[2];vy[6]=vy[2]-height;
vx[7]=vx[3];vy[7]=vy[3]-height;
for(i=0;i<3;i++){
j=dashed[i];
dashedline(vx[3],vy[3],vx[j],vy[j],255,255,255);
}
draw3d( );
for(i=0;i<11;i++){
j=solid[i];k=solid[i+1];
line(vx[j],vy[j],vx[k],vy[k],255,255,255);
}
}
void getline(int line,unsigned char *pixel)
{
xms.target.part[0]=FP_OFF(pixel);
xms.target.part[1]=FP_SEG(pixel);
xms.target_handle=0;
xms.length=byteperpixel*(right-left);
xms.source_handle=handle;
xms.source.offset=byteperpixel*((unsigned
long)WIDTH*line+left);
move_xms(&xms);
}
void formbmp( )
{
int i,line,bmpwidth,bmpheight;
unsigned char *pixel;
FILE *fp;
if((fp=fopen("surface.bmp","wb"))==NULL) {
printf("Can't write to file %s!\n",
"surface.bmp");
exit(1);
}
bmpwidth=right-left;bmpheight=bottom-top;
head.type[0]='B';head.type[1]='M';
head.size=(long)bmpwidth*bmpheight*3+0x36;
head.reserved=0;
head.offset=0x36;
fwrite(&head,sizeof(head),1,fp);
bmp.size=0x28;
bmp.width=bmpwidth;
bmp.height=bmpheight;
bmp.plane=1;
bmp.bitcount=0x18;
bmp.compression=0;
bmp.imagesize=(long)bmpwidth*bmpheight*3;
bmp.xpels=0xece;
bmp.ypels=0xec4;
bmp.colorused=0;
bmp.colorimportant=0;
fwrite(&bmp,sizeof(bmp),1,fp);
pixel=malloc(4*bmpwidth*sizeof
(unsigned char));
for(line=bottom;line>top;line--) {
getline(line,pixel);
for(i=0;i<bmpwidth;i++) {
fputc(pixel[4*i],fp);
fputc(pixel[4*i+1],fp);
fputc(pixel[4*i+2],fp);
}
}
fclose(fp); free(pixel);
}
main( )
{
int size;
unsigned long offset;
WIDTH=640;HEIGHT=480;byteperpixel=4;
left=100;top=100;right=500;bottom=420;
offset=(unsigned long)byteperpixel
*WIDTH*HEIGHT;
size=offset>>10;
xmsinitial(size+100);
cleardevice(0,0,0);
surface( );
formbmp( );
free_xms(handle);
textmode(0x3);
}
|