henesyinit from p9f47575dc5 years agoHistory
420 lines · 9.4 KB · C
RawDownload
/* * anti-aliased isoplot into a file * does this really obey window? */#include <u.h>#include <libc.h>#include <libg.h>#include <fb.h>#include <stdio.h>float **data;int ndata;typedef struct Pixel{	unsigned char m, a;}Pixel;Pixel **pic;int wid=640, hgt=512;typedef struct Acc{	float accm, acca;	float m, a;}Acc;Acc *col;int lo, hi;float *line, *linealpha, *stripe, *stripealpha;#define	NLIGHT	16int nlight=1;struct light{	float lx, ly, lz;	/* direction to light */	float lum;		/* brightness of light */	float sx, sy, sz;	/* direction to hilite */}light[NLIGHT]={	2, 3, 9, 1, 0, 0};float spec=0;			/* amount of specular reflection */float bump=80;			/* exponent of specular bump */float diff=.98;			/* amount of diffuse reflection */float ambient=.02;		/* amount of ambient light */double range;void erread(int f, char *p, int n){	if(read(f, p, n)!=n){		fprint(2, "aplot: eof!\n");		exits("eof");	}}#define	cvt(name, type)\void name(int f, float *fp, int n)\{\	type line[8192];	/* bug, could be too small! */\	type *lp=line;\	int i;\	erread(f, (char *)line, n*sizeof(type));\	for(i=0;i!=n;i++)\		*fp++=*lp++;\}cvt(cint, int);cvt(cshort, short);cvt(clong, long);cvt(cdouble, double);cvt(cchar, char);cvt(cuchar, unsigned char);void cfloat(int f, float *fp, int n){	erread(f, (char *)fp, n*sizeof(float));}void getlights(char *);int size(int, int);void fixlights(void);void adraw(int);void *emalloc(long n){	void *v=malloc(n);	if(v==0){		fprint(2, "aplot: no space\n");		exits("no space");	}	return v;}main(int argc, char *argv[]){	float hi=0, scale;	register i, j, f;	char *picargv[10];	char window[1024];	char *line;	void (*crack)(int, float *, int);	int x0=0, y0=0;	PICFILE *outf;	/* Crack flags */	if(getflags(argc, argv, "al:1[lightfile]t:1[type]r:1[range]w:4[x0 y0 x1 y1]")!=2)		usage("infile");	if(flag['l']) getlights(flag['l'][0]);	if(flag['r']) range=atof(flag['r'][0]);	if(flag['w']){		x0=atoi(flag['w'][0]);		y0=atoi(flag['w'][1]);		wid=atoi(flag['w'][2]-x0);		hgt=atoi(flag['w'][3]-y0);	}	if(wid<=0 || hgt<=0){		fprint(2, "%s: output window too small (%dx%d)\n", argv[0], wid, hgt);		exits("window too small");	}	pic=emalloc(hgt*sizeof(Pixel *));	pic[0]=emalloc(wid*hgt*sizeof(Pixel));	memset(pic[0], 0, wid*hgt*sizeof(Pixel));	for(i=1;i!=hgt;i++) pic[i]=pic[i-1]+wid;	line=emalloc(2*wid*sizeof(char));	col=emalloc(hgt*sizeof(Acc));	line=emalloc(hgt*sizeof(float));	linealpha=emalloc(hgt*sizeof(float));	stripe=emalloc(hgt*sizeof(float));	stripealpha=emalloc(hgt*sizeof(float));	lo=hgt;	hi=0;	switch(flag['t']?flag['t'][0][0]:'f'){	case 's': i=sizeof(short);	crack=cshort;	break;	case 'i': i=sizeof(int);	crack=cint;	break;	case 'l': i=sizeof(long);	crack=clong;	break;	case 'f': i=sizeof(float);	crack=cfloat;	break;	case 'd': i=sizeof(double);	crack=cdouble;	break;	case 'c': i=sizeof(char);	crack=cchar;	break;	case 'u': i=sizeof(unsigned char);crack=cuchar;	break;	default: fprint(2, "bad type %c\n", flag['t'][0][0]); exits("bad type");	}	/* Check and read input */	if((f=open(argv[1], 0))<0){		perror(argv[1]);		exits("open input");	}	ndata=size(f, i);	if(ndata<=0){		fprint(2, "%s: data file too small (ndata=%d)\n", argv[0], ndata);		exits("too small");	}	data=emalloc(ndata*sizeof(float *));	data[0]=emalloc(ndata*ndata*sizeof(float));	for(i=1;i!=ndata;i++) data[i]=data[i-1]+ndata;	fixlights();	for(i=0;i!=ndata;i++){		(*crack)(f, data[i], ndata);		for(j=0;j!=ndata;j++)			if(fabs(data[i][j])>hi)hi=fabs(data[i][j]);	}	fprint(2, "size %dx%d, range %g\n", ndata, ndata, hi);	/* Create output */	outf=picopen_w("OUT", "runcode", x0, y0, wid, hgt, flag['a']?"m":"ma", argv, 0);	if(outf==0){		perror("OUT");		exits("creat output");	}	/* Rescale input data */	scale=flag['r']?range:hi;	if(scale!=0.){		for(i=0;i!=ndata;i++)for(j=0;j!=ndata;j++)			data[i][j]*=ndata/scale;	}	/* Draw image */	for(j=0;j!=wid;j++)		adraw(j);	/* Write output */	for(i=0;i!=hgt;i++){		if(flag['a']){			for(j=0;j!=wid;j++)				line[j]=pic[i][j].m;		}		else{			for(j=0;j!=wid;j++){				line[2*j]=pic[i][j].m;				line[2*j+1]=pic[i][j].a;			}		}		picwrite(outf, line);	}	exits("");}int size(int f, int l){	Dir stbuf;	register i;	dirfstat(f, &stbuf);	for(i=0;i*i*l<stbuf.length;i++);	if(i*i*l!=stbuf.length)		fprint(2, "Non-square file padded to %dx%d\n", i, i);	return i;}float sample(int x, int y){	if(x<0) x=0; else if(ndata<=x) x=ndata-1;	if(y<0) y=0; else if(ndata<=y) y=ndata-1;	return data[y][x];}double fmin(double a, double b){ return a<b?a:b; }int min(int a, int b){ return a<b?a:b; }double fmax(double a, double b){ return a>b?a:b; }int max(int a, int b){ return a>b?a:b; }int clamp(double a){	return a<0?0:a<255?a:255;}float intens(int x, int y){	struct light *l, *el=&light[nlight];	float nx, ny, nz, v, len;	nx=sample(x+1, y)-sample(x-1, y);	ny=sample(x, y+1)-sample(x, y-1);	nz=2;	len=sqrt(nx*nx+ny*ny+nz*nz);	nx/=len;	ny/=len;	nz/=len;	v=ambient;	for(l=light;l!=el;l++)		v+=l->lum*(diff*fmax(nx*l->lx+ny*l->ly+nz*l->lz, 0.)			+spec*pow(fmax(nx*l->sx+ny*l->sy+nz*l->sz, 0.), bump));	return v;}typedef struct{	int x, y, z;	float tx, tz, pv;}Point3d;int inside(Point3d p){	return(0<=p.x && p.x<ndata && 0<=p.y && p.y<ndata);}Point3d add3(Point3d p, Point3d q){	p.x+=q.x;	p.y+=q.y;	p.z+=q.z;	return(p);}Point3d Pt3(int x, int y, int z){	Point3d p;	p.x=x;	p.y=y;	p.z=z;	return(p);}/* * samples transformed into screen coordinates */void tsample(Point3d *p){	p->tz=sample(p->x, p->y)+(p->x+p->y)/2.+hgt/4;	p->tx=p->y-p->x+wid/2;	p->pv=intens(p->x, p->y);}void flushline(void);void accumulate(Point3d, Point3d, Point3d);void flushstripe(int);/* * draw an antialised vertical stripe of the picture in pic[.][j]. * This stripe maps into the line y=j-wid/2+x in the data array. * Points [x, y, f(x, y)] map to [(x+y)/2+f(x, y)+hgt/4, y-x+wid/2] * In front to back order, we accumulate sub-stripes into an array that * gets composited into the ultimate vertical scanline and zeroed every time the * stripe changes direction from up to down or vice versa. */#define	trap(a, b) ((b.tx-a.tx)*(a.tz+b.tz))void adraw(int j){	int dir=0, plo;	Point3d p, q, r;	p.x=0;	p.y=j-ndata;	tsample(&p);	q=add3(p, Pt3(0, 1, 0));	if(!inside(p)){		p=add3(p, Pt3(-p.y, -p.y, 0));		tsample(&p);		if(!inside(p))			return;	}	tsample(&q);	if(!inside(q)){		q=add3(q, Pt3(-q.y, -q.y, 0));		tsample(&q);		if(!inside(q))			return;	}	for(;;){		plo=p.x+p.y<q.x+q.y;		if(plo)			r=add3(p, Pt3(1, 1, 0));		else			r=add3(q, Pt3(1, 1, 0));		if(!inside(r))			break;		tsample(&r);		if((trap(p, q)+trap(q, r)<trap(p, r))!=dir){			flushline();			dir=!dir;		}		accumulate(p, q, r);		if(plo)			p=r;		else			q=r;	}	flushstripe(j);}void flushline(void){	int i;	for(i=lo;i<=hi;i++){		if(stripe[i]<1. && fabs(col[i].a-col[i].acca)>1e-3){			col[i].m+=col[i].accm*(1-col[i].a);			col[i].a+=col[i].acca*(1-col[i].a);		}		col[i].accm=0;		col[i].acca=0;	}	lo=hgt;	hi=0;}void flushstripe(int j){	int i;	flushline();	for(i=0;i!=hgt;i++){		pic[hgt-1-i][j].m=clamp(col[i].m*256);		pic[hgt-1-i][j].a=clamp(col[i].a*256);		col[i].m=0;		col[i].a=0;	}}void accumulate(Point3d p, Point3d q, Point3d r){	Point3d s, t;	register float a, newa, da, y, z, dz, z0, z1, pv;	pv=r.pv;	/* sort so that p.tz<=q.tz<=r.tz */	if(p.tz>q.tz){ t=p; p=q; q=t; }	if(q.tz>r.tz){ t=q; q=r; r=t; }	if(p.tz>q.tz){ t=p; p=q; q=t; }	if(r.tz==p.tz)		return;	s.tz=q.tz;	s.tx=p.tx+(r.tx-p.tx)*(q.tz-p.tz)/(r.tz-p.tz);	if(q.tx>s.tx){ t=q; q=s; s=t; }	/* p.tz<=q.tz==s.tz<=r.tz and q.tx<=s.tx */	if(p.tz!=q.tz){		y=(s.tx-q.tx)/(q.tz-p.tz)/2.;		a=0.;		z0=ceil(p.tz);		z1=ceil(q.tz);		for(z=z0;z<=z1;z+=1){			dz=fmin(z, q.tz)-p.tz;			newa=dz*dz*y;			da=newa-a;			if(0<z && z<=hgt){				col[(int)z-1].accm+=da*pv;				col[(int)z-1].acca+=da;			}			a=newa;		}	}	if(r.tz!=q.tz){		y=(s.tx-q.tx)/(r.tz-q.tz)/2.;		a=0.;		z0=floor(r.tz);		z1=floor(q.tz);		for(z=z0;z>=z1;z-=1){			dz=r.tz-fmax(z, q.tz);			newa=dz*dz*y;			da=newa-a;			if(0<=z && z<hgt){				col[(int)z].accm+=da*pv;				col[(int)z].acca+=da;			}			a=newa;		}	}	lo=max(0, min((int)floor(p.tz), lo));	hi=min(hgt-1, max((int)ceil(r.tz), hi));}void fixlights(void){	register struct light *lp, *el=&light[nlight];	float l;	for(lp=light;lp!=el;lp++){		l=sqrt(lp->lx*lp->lx+lp->ly*lp->ly+lp->lz*lp->lz);		if(l!=0.){			lp->lx/=l;			lp->ly/=l;			lp->lz/=l;		}		lp->sx=lp->lx+.5;		lp->sy=lp->ly+.5;		lp->sz=lp->lz+sqrt(.5);		l=sqrt(lp->sx*lp->sx+lp->sy*lp->sy+lp->sz*lp->sz);		if(l!=0.){			lp->sx/=l;			lp->sy/=l;			lp->sz/=l;		}	}}void getlights(char *name){	register struct light *lp=light;	register FILE *fd;	double x, y, z, lum;	char line[512];	if((fd=fopen(name, "r"))==NULL){		perror(name);		exits("open lights");	}	while(fgets(line, sizeof line, fd)!=NULL){		if(sscanf(line, "light%lf%lf%lf%lf", &x, &y, &z, &lum)==4){			if(lp==&light[NLIGHT]){				fprint(2, "aplot: can only do %d lights\n",					NLIGHT);				exits("too many lights");			}			lp->lx=x;			lp->ly=y;			lp->lz=z;			lp->lum=lum;			lp++;		}else if(sscanf(line, "ambient%lf", &x)==1)			ambient=x;		else if(sscanf(line, "spec%lf", &x)==1)			spec=x;		else if(sscanf(line, "diff%lf", &x)==1)			diff=x;		else if(sscanf(line, "bump%lf", &x)==1)			bump=x;		else{			if(line[0])				line[strlen(line-1)]='\0';			fprint(2, "aplot: what means `%s'?\n", line);		}	}	nlight=lp-light;	fclose(fd);		}