/* * anti-aliased isoplot into a file * does this really obey window? */ #include #include #include #include #include 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 16 int 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*lb?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.xtz=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.y1e-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=z1;z-=1){ dz=r.tz-fmax(z, q.tz); newa=dz*dz*y; da=newa-a; if(0<=z && zlx*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); }