void getfocus( /* set focus distance */ char *s ) { char buf[64]; double dist; if (sscanf(s, "%lf", &dist) < 1) { int x, y; RAY thisray; if (dev->getcur == NULL) return; (*dev->comout)("Pick focus point\n"); if ((*dev->getcur)(&x, &y) == ABORT) return; if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) { error(COMMAND, "not on image"); return; } rayorigin(&thisray, PRIMARY, NULL, NULL); if (!localhit(&thisray, &thescene)) { error(COMMAND, "not a local object"); return; } dist = thisray.rot; } else if (dist <= .0) { error(COMMAND, "focus distance must be positive"); return; } ourview.vdist = dist; sprintf(buf, "Focus distance set to %f\n", dist); (*dev->comout)(buf); }
static double l_psize(char *nm) /* compute pixel size in steradians */ { static unsigned long ltick[MAXINP]; static double psize[MAXINP]; FVECT dir0, org, dirx, diry; RREAL locx[2], locy[2]; double d; int fn; register int i; d = argument(1); if (d <= -0.5 || d >= nfiles+0.5) { errno = EDOM; return(0.0); } if (d < 0.5) return((double)nfiles); fn = d - 0.5; if (ltick[fn] != eclock) { /* need to compute? */ psize[fn] = 0.0; if (input[fn].vw.type == 0) errno = EDOM; else if (input[fn].vw.type != VT_PAR && funvalue(vray[6], 1, &d) >= -FTINY) { for (i = 0; i < 3; i++) dir0[i] = funvalue(vray[3+i], 1, &d); pix2loc(locx, &input[fn].rs, xscan+1, ymax-1-yscan); pix2loc(locy, &input[fn].rs, xscan, ymax-yscan); if (viewray(org, dirx, &input[fn].vw, locx[0], locx[1]) >= -FTINY && viewray(org, diry, &input[fn].vw, locy[0], locy[1]) >= -FTINY) { /* approximate solid angle */ for (i = 0; i < 3; i++) { dirx[i] -= dir0[i]; diry[i] -= dir0[i]; } fcross(dir0, dirx, diry); psize[fn] = VLEN(dir0); } } ltick[fn] = eclock; } return(psize[fn]); }
int getinterest( /* get area of interest */ char *s, int direc, FVECT vec, double *mp ) { int x, y; RAY thisray; int i; if (sscanf(s, "%lf", mp) != 1) *mp = 1.0; else if (*mp < -FTINY) /* negative zoom is reduction */ *mp = -1.0 / *mp; else if (*mp <= FTINY) { /* too small */ error(COMMAND, "illegal magnification"); return(-1); } if (!sscanvec(sskip(s), vec)) { if (dev->getcur == NULL) return(-1); (*dev->comout)("Pick view center\n"); if ((*dev->getcur)(&x, &y) == ABORT) return(-1); if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) { error(COMMAND, "not on image"); return(-1); } if (!direc || ourview.type == VT_PAR) { rayorigin(&thisray, PRIMARY, NULL, NULL); if (!localhit(&thisray, &thescene)) { error(COMMAND, "not a local object"); return(-1); } } if (direc) if (ourview.type == VT_PAR) for (i = 0; i < 3; i++) vec[i] = thisray.rop[i] - ourview.vp[i]; else VCOPY(vec, thisray.rdir); else VCOPY(vec, thisray.rop); } else if (direc) { for (i = 0; i < 3; i++) vec[i] -= ourview.vp[i]; if (normalize(vec) == 0.0) { error(COMMAND, "point at view origin"); return(-1); } } return(0); }
static int moveview( /* move our view */ int dx, int dy, int mov, int orb ) { VIEW nv; FVECT odir, v1; double d; int li; /* start with old view */ nv = odev.v; /* change view direction */ if (mov | orb) { if ((li = qtFindLeaf(dx, dy)) < 0) return(0); /* not on window */ VSUM(odir, qtL.wp[li], nv.vp, -1.); } else { if (viewray(nv.vp, nv.vdir, &odev.v, (dx+.5)/odev.hres, (dy+.5)/odev.vres) < -FTINY) return(0); /* outside view */ } if (orb && mov) { /* orbit left/right */ spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov); VSUM(nv.vp, qtL.wp[li], odir, -1.); spinvector(nv.vdir, nv.vdir, nv.vup, d); } else if (orb) { /* orbit up/down */ if (geodesic(odir, odir, nv.vup, d=MOVDEG*PI/180.*orb, GEOD_RAD) == 0.0) return(0); VSUM(nv.vp, qtL.wp[li], odir, -1.); geodesic(nv.vdir, nv.vdir, nv.vup, d, GEOD_RAD); } else if (mov) { /* move forward/backward */ d = MOVPCT/100. * mov; VSUM(nv.vp, nv.vp, odir, d); } if (!mov ^ !orb && headlocked) { /* restore head height */ VSUM(v1, odev.v.vp, nv.vp, -1.); d = DOT(v1, odev.v.vup); VSUM(nv.vp, nv.vp, odev.v.vup, d); } if (setview(&nv) != NULL) return(0); /* illegal view */ dev_view(&nv); inpresflags |= DFL(DC_SETVIEW); return(1); }
void getorigin( /* origin viewpoint */ char *s ) { VIEW nv = ourview; double d; /* get new view origin */ if (sscanf(s, "%lf %lf", &d, &d) == 1) { /* just moving some distance */ VSUM(nv.vp, nv.vp, nv.vdir, d); } else if (!sscanvec(s, nv.vp)) { int x, y; /* need to pick origin */ RAY thisray; if (dev->getcur == NULL) return; (*dev->comout)("Pick point on surface for new origin\n"); if ((*dev->getcur)(&x, &y) == ABORT) return; if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) { error(COMMAND, "not on image"); return; } rayorigin(&thisray, PRIMARY, NULL, NULL); if (!localhit(&thisray, &thescene)) { error(COMMAND, "not a local object"); return; } if (thisray.rod < 0.0) /* don't look through other side */ flipsurface(&thisray); VSUM(nv.vp, thisray.rop, thisray.ron, 20.0*FTINY); VCOPY(nv.vdir, thisray.ron); } else if (!sscanvec(sskip2(s,3), nv.vdir) || normalize(nv.vdir) == 0.0) VCOPY(nv.vdir, ourview.vdir); d = DOT(nv.vdir, nv.vup); /* need different up vector? */ if (d*d >= 1.-2.*FTINY) { int i; nv.vup[0] = nv.vup[1] = nv.vup[2] = 0.0; for (i = 3; i--; ) if (nv.vdir[i]*nv.vdir[i] < 0.34) break; nv.vup[i] = 1.; } newview(&nv); }
static int moveview( /* move our view */ int dx, int dy, int mov, int orb ) { VIEW nv; FVECT odir, v1, wp; double d; /* start with old view */ nv = thisview; /* change view direction */ if ((d = viewray(v1, odir, &thisview, (dx+.5)/hres, (dy+.5)/vres)) < -FTINY) return(0); /* outside view */ if (mov | orb) { if (!getintersect(wp, v1, odir, d)) return(0); VSUM(odir, wp, nv.vp, -1.); } else VCOPY(nv.vdir, odir); if (orb && mov) { /* orbit left/right */ spinvector(odir, odir, nv.vup, d=MOVDEG*PI/180.*mov); VSUM(nv.vp, wp, odir, -1.); spinvector(nv.vdir, nv.vdir, nv.vup, d); } else if (orb) { /* orbit up/down */ if (geodesic(odir, odir, nv.vup, d=MOVDEG*PI/180.*orb, GEOD_RAD) == 0.0) return(0); VSUM(nv.vp, wp, odir, -1.); geodesic(nv.vdir, nv.vdir, nv.vup, d, GEOD_RAD); } else if (mov) { /* move forward/backward */ d = MOVPCT/100. * mov; VSUM(nv.vp, nv.vp, odir, d); } if (!mov ^ !orb && headlocked) { /* restore head height */ VSUM(v1, thisview.vp, nv.vp, -1.); d = DOT(v1, thisview.vup); VSUM(nv.vp, nv.vp, thisview.vup, d); } if (setview(&nv) != NULL) return(0); /* illegal view */ dev_view(&nv); return(1); }
static double l_ray( /* return ray origin or direction */ register char *nam ) { static unsigned long ltick[MAXINP]; static FVECT lorg[MAXINP], ldir[MAXINP]; static double ldist[MAXINP]; RREAL loc[2]; double d; int fn; register int i; d = argument(1); if (d <= -0.5 || d >= nfiles+0.5) { errno = EDOM; return(0.0); } if (d < 0.5) return((double)nfiles); fn = d - 0.5; if (ltick[fn] != eclock) { /* need to compute? */ lorg[fn][0] = lorg[fn][1] = lorg[fn][2] = 0.0; ldir[fn][0] = ldir[fn][1] = ldir[fn][2] = 0.0; ldist[fn] = -1.0; if (input[fn].vw.type == 0) errno = EDOM; else { pix2loc(loc, &input[fn].rs, xscan, ymax-1-yscan); ldist[fn] = viewray(lorg[fn], ldir[fn], &input[fn].vw, loc[0], loc[1]); } ltick[fn] = eclock; } if (nam == vray[i=6]) return(ldist[fn]); while (i--) if (nam == vray[i]) return(i < 3 ? lorg[fn][i] : ldir[fn][i-3]); eputs("Bad call to l_ray()!\n"); quit(1); return 1; /* pro forma return */ }
void traceray( /* trace a single ray */ char *s ) { RAY thisray; char buf[512]; thisray.rmax = 0.0; if (!sscanvec(s, thisray.rorg) || !sscanvec(sskip2(s,3), thisray.rdir)) { int x, y; if (dev->getcur == NULL) return; (*dev->comout)("Pick ray\n"); if ((*dev->getcur)(&x, &y) == ABORT) return; if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, (x+.5)/hresolu, (y+.5)/vresolu)) < -FTINY) { error(COMMAND, "not on image"); return; } } else if (normalize(thisray.rdir) == 0.0) { error(COMMAND, "zero ray direction"); return; } ray_trace(&thisray); if (thisray.ro == NULL) (*dev->comout)("ray hit nothing"); else { OBJREC *mat = NULL; OBJREC *mod = NULL; char matspec[256]; OBJREC *ino; matspec[0] = '\0'; if (thisray.ro->omod != OVOID) { mod = objptr(thisray.ro->omod); mat = findmaterial(mod); } if (thisray.rod < 0.0) strcpy(matspec, "back of "); if (mod != NULL) { strcat(matspec, mod->oname); if (mat != mod && mat != NULL) sprintf(matspec+strlen(matspec), " (%s)", mat->oname); } else strcat(matspec, VOIDID); sprintf(buf, "ray hit %s %s \"%s\"", matspec, ofun[thisray.ro->otype].funame, thisray.ro->oname); if ((ino = objptr(thisray.robj)) != thisray.ro) sprintf(buf+strlen(buf), " in %s \"%s\"", ofun[ino->otype].funame, ino->oname); (*dev->comout)(buf); (*dev->comin)(buf, NULL); if (thisray.rot >= FHUGE) (*dev->comout)("at infinity"); else { sprintf(buf, "at (%.6g %.6g %.6g) (%.6g)", thisray.rop[0], thisray.rop[1], thisray.rop[2], raydistance(&thisray)); (*dev->comout)(buf); } (*dev->comin)(buf, NULL); sprintf(buf, "value (%.5g %.5g %.5g) (%.3gL)", colval(thisray.rcol,RED), colval(thisray.rcol,GRN), colval(thisray.rcol,BLU), luminance(thisray.rcol)); (*dev->comout)(buf); } (*dev->comin)(buf, NULL); }
int paint( /* compute and paint a rectangle */ PNODE *p ) { static RAY thisray; double h, v; if ((p->xmax <= p->xmin) | (p->ymax <= p->ymin)) { /* empty */ p->x = p->xmin; p->y = p->ymin; setcolor(p->v, 0.0, 0.0, 0.0); return(0); } /* jitter ray direction */ p->x = h = p->xmin + (p->xmax-p->xmin)*frandom(); p->y = v = p->ymin + (p->ymax-p->ymin)*frandom(); if ((thisray.rmax = viewray(thisray.rorg, thisray.rdir, &ourview, h/hresolu, v/vresolu)) < -FTINY) { setcolor(thisray.rcol, 0.0, 0.0, 0.0); } else if (!ray_pnprocs) { /* immediate mode */ ray_trace(&thisray); } else { /* queuing mode */ int rval; rayorigin(&thisray, PRIMARY, NULL, NULL); thisray.rno = (RNUMBER)p; rval = ray_pqueue(&thisray); if (!rval) return(0); if (rval < 0) return(-1); /* get node for returned ray */ p = (PNODE *)thisray.rno; } copycolor(p->v, thisray.rcol); scalecolor(p->v, exposure); recolor(p); /* paint it */ if (dev->flush != NULL) { /* shall we check for input? */ static RNUMBER lastflush = 0; RNUMBER counter = raynum; int flushintvl; if (!ray_pnprocs) { counter = nrays; flushintvl = WFLUSH1; } else if (ambounce == 0) flushintvl = ray_pnprocs*WFLUSH; else if (niflush < WFLUSH) flushintvl = ray_pnprocs*niflush/(ambounce+1); else flushintvl = ray_pnprocs*WFLUSH/(ambounce+1); if (lastflush > counter) lastflush = 0; /* counter wrapped */ if (counter - lastflush >= flushintvl) { lastflush = counter; (*dev->flush)(); niflush++; } } return(1); }
extern void /* add sources smaller than rad to computed subimage */ drawsources( COLOR *pic[], /* subimage pixel value array */ float *zbf[], /* subimage distance array (opt.) */ int x0, /* origin and size of subimage */ int xsiz, int y0, int ysiz ) { RREAL spoly[MAXVERT][2], ppoly[MAXVERT][2]; int nsv, npv; int xmin, xmax, ymin, ymax, x, y; RREAL cxy[2]; double w; RAY sr; register SPLIST *sp; register int i; /* check each source in our list */ for (sp = sphead; sp != NULL; sp = sp->next) { /* clip source poly to subimage */ nsv = box_clip_poly(sp->vl, sp->nv, (double)x0/hres, (double)(x0+xsiz)/hres, (double)y0/vres, (double)(y0+ysiz)/vres, spoly); if (!nsv) continue; /* find common subimage (BBox) */ xmin = x0 + xsiz; xmax = x0; ymin = y0 + ysiz; ymax = y0; for (i = 0; i < nsv; i++) { if ((double)xmin/hres > spoly[i][0]) xmin = spoly[i][0]*hres + FTINY; if ((double)xmax/hres < spoly[i][0]) xmax = spoly[i][0]*hres - FTINY; if ((double)ymin/vres > spoly[i][1]) ymin = spoly[i][1]*vres + FTINY; if ((double)ymax/vres < spoly[i][1]) ymax = spoly[i][1]*vres - FTINY; } /* evaluate each pixel in BBox */ for (y = ymin; y <= ymax; y++) for (x = xmin; x <= xmax; x++) { /* subarea for pixel */ npv = box_clip_poly(spoly, nsv, (double)x/hres, (x+1.)/hres, (double)y/vres, (y+1.)/vres, ppoly); if (!npv) continue; /* no overlap */ convex_center(ppoly, npv, cxy); if ((sr.rmax = viewray(sr.rorg,sr.rdir,&ourview, cxy[0],cxy[1])) < -FTINY) continue; /* not in view */ if (source[sp->sn].sflags & SSPOT && spotout(&sr, source[sp->sn].sl.s)) continue; /* outside spot */ rayorigin(&sr, SHADOW, NULL, NULL); sr.rsrc = sp->sn; rayvalue(&sr); /* compute value */ if (bright(sr.rcol) <= FTINY) continue; /* missed/blocked */ /* modify pixel */ w = poly_area(ppoly, npv) * hres * vres; if (zbf[y-y0] != NULL && sr.rt < 0.99*zbf[y-y0][x-x0]) { zbf[y-y0][x-x0] = sr.rt; } else if (!bigdiff(sr.rcol, pic[y-y0][x-x0], 0.01)) { /* source sample */ scalecolor(pic[y-y0][x-x0], w); continue; } scalecolor(sr.rcol, w); scalecolor(pic[y-y0][x-x0], 1.-w); addcolor(pic[y-y0][x-x0], sr.rcol); } } }
void addpicz( /* add a picture + depth-buffer */ char *pcf, char *zbf ) { FILE *pfp; int zfd; COLR *cscn; float *zscn; struct phead phd; int eshft; double emult; RESOLU prs; RREAL vl[2]; FVECT ro, rd; double aftd; COLOR ctmp; int j; register int i; /* open files */ if ((pfp = fopen(pcf, "r")) == NULL) { sprintf(errmsg, "cannot open picture file \"%s\"", pcf); error(SYSTEM, pcf); } if ((zfd = open(zbf, O_RDONLY)) < 0) { sprintf(errmsg, "cannot open depth file \"%s\"", zbf); error(SYSTEM, pcf); } /* load picture header */ phd.vw = stdview; phd.expos = 1.0; phd.badfmt = phd.gotview = phd.altprims = 0; if (getheader(pfp, picheadline, &phd) < 0 || phd.badfmt || !fgetsresolu(&prs, pfp)) { sprintf(errmsg, "bad format for picture file \"%s\"", pcf); error(USER, errmsg); } if (!phd.gotview || setview(&phd.vw) != NULL) { sprintf(errmsg, "missing/illegal view in picture \"%s\"", pcf); error(USER, errmsg); } if (phd.altprims) { sprintf(errmsg, "ignoring primary values in picture \"%s\"", pcf); error(WARNING, errmsg); } /* figure out what to do about exposure */ if ((phd.expos < 0.99) | (phd.expos > 1.01)) { emult = -log(phd.expos)/log(2.); eshft = emult >= 0. ? emult+.5 : emult-.5; emult -= (double)eshft; if ((emult <= 0.01) & (emult >= -0.01)) emult = -1.; else { emult = 1./phd.expos; eshft = 0; } } else { emult = -1.; eshft = 0; } /* allocate buffers */ cscn = (COLR *)malloc(scanlen(&prs)*sizeof(COLR)); zscn = (float *)malloc(scanlen(&prs)*sizeof(float)); if ((cscn == NULL) | (zscn == NULL)) error(SYSTEM, "out of memory in addpicz"); /* read and process each scanline */ for (j = 0; j < numscans(&prs); j++) { i = scanlen(&prs); /* read colrs */ if (freadcolrs(cscn, i, pfp) < 0) { sprintf(errmsg, "error reading picture \"%s\"", pcf); error(USER, errmsg); } if (eshft) /* shift exposure */ shiftcolrs(cscn, i, eshft); i *= sizeof(float); /* read depth */ if (read(zfd, (char *)zscn, i) != i) { sprintf(errmsg, "error reading depth file \"%s\"", zbf); error(USER, errmsg); } for (i = scanlen(&prs); i--; ) { /* do each pixel */ pix2loc(vl, &prs, i, j); aftd = viewray(ro, rd, &phd.vw, vl[0], vl[1]); if (aftd < -FTINY) continue; /* off view */ if (aftd > FTINY && zscn[i] > aftd) continue; /* aft clipped */ if (emult > 0.) { /* whatta pain */ colr_color(ctmp, cscn[i]); scalecolor(ctmp, emult); setcolr(cscn[i], colval(ctmp,RED), colval(ctmp,GRN), colval(ctmp,BLU)); } addray(ro, rd, (double)zscn[i], cscn[i]); } } /* write output and free beams */ hdflush(NULL); /* clean up */ free((void *)cscn); free((void *)zscn); fclose(pfp); close(zfd); }