--- ray/src/rt/rv3.c 1994/12/20 20:18:41 2.6 +++ ray/src/rt/rv3.c 2010/10/09 22:38:35 2.34 @@ -1,41 +1,41 @@ -/* Copyright (c) 1994 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: rv3.c,v 2.34 2010/10/09 22:38:35 greg Exp $"; #endif - /* * rv3.c - miscellaneous routines for rview. * - * 5/11/87 + * External symbols declared in rpaint.h */ -#include "ray.h" +#include "copyright.h" -#include "octree.h" +#include +#include "ray.h" #include "rpaint.h" - #include "random.h" #ifndef WFLUSH -#ifdef SPEED -#define WFLUSH (5*SPEED) -#else -#define WFLUSH 100 /* flush after this many rays */ +#define WFLUSH 64 /* flush after this many primary rays */ #endif +#ifndef WFLUSH1 +#define WFLUSH1 512 /* or this many total rays */ #endif + #ifdef SMLFLT #define sscanvec(s,v) (sscanf(s,"%f %f %f",v,v+1,v+2)==3) #else #define sscanvec(s,v) (sscanf(s,"%lf %lf %lf",v,v+1,v+2)==3) #endif +static RNUMBER niflush; /* flushes since newimage() */ -getrect(s, r) /* get a box */ -char *s; -register RECT *r; +int +getrect( /* get a box */ + char *s, + RECT *r +) { int x0, y0, x1, y1; @@ -79,15 +79,17 @@ register RECT *r; } -getinterest(s, direc, vec, mp) /* get area of interest */ -char *s; -int direc; -FVECT vec; -double *mp; +int +getinterest( /* get area of interest */ + char *s, + int direc, + FVECT vec, + double *mp +) { int x, y; RAY thisray; - register int i; + int i; if (sscanf(s, "%lf", mp) != 1) *mp = 1.0; @@ -109,7 +111,7 @@ double *mp; return(-1); } if (!direc || ourview.type == VT_PAR) { - rayorigin(&thisray, NULL, PRIMARY, 1.0); + rayorigin(&thisray, PRIMARY, NULL, NULL); if (!localhit(&thisray, &thescene)) { error(COMMAND, "not a local object"); return(-1); @@ -123,16 +125,22 @@ double *mp; VCOPY(vec, thisray.rdir); else VCOPY(vec, thisray.rop); - } else if (direc) - for (i = 0; i < 3; i++) - vec[i] -= ourview.vp[i]; + } 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); } float * /* keep consistent with COLOR typedef */ -greyof(col) /* convert color to greyscale */ -register COLOR col; +greyof( /* convert color to greyscale */ + COLOR col +) { static COLOR gcol; double b; @@ -142,70 +150,163 @@ register COLOR col; return(gcol); } +static void +recolor( /* recolor the given node */ + PNODE *p +) +{ + while (p->kid != NULL) { /* need to propogate down */ + int mx = (p->xmin + p->xmax) >> 1; + int my = (p->ymin + p->ymax) >> 1; + int ki; + if (p->x >= mx) + ki = (p->y >= my) ? UR : DR; + else + ki = (p->y >= my) ? UL : DL; + pcopy(p, p->kid+ki); + p = p->kid + ki; + } -paint(p, xmin, ymin, xmax, ymax) /* compute and paint a rectangle */ -register PNODE *p; -int xmin, ymin, xmax, ymax; + (*dev->paintr)(greyscale?greyof(p->v):p->v, + p->xmin, p->ymin, p->xmax, p->ymax); +} + +int +paint( /* compute and paint a rectangle */ + PNODE *p +) { - extern unsigned long nrays; - static unsigned long lastflush = 0; static RAY thisray; double h, v; - if (xmax - xmin <= 0 || ymax - ymin <= 0) { /* empty */ - p->x = xmin; - p->y = ymin; + 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; + return(0); } /* jitter ray direction */ - h = xmin + (xmax-xmin)*frandom(); - v = ymin + (ymax-ymin)*frandom(); + 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 { - rayorigin(&thisray, NULL, PRIMARY, 1.0); - samplendx++; - rayvalue(&thisray); + } else if (nproc == 1) { /* 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; } - p->x = h; - p->y = v; copycolor(p->v, thisray.rcol); scalecolor(p->v, exposure); - (*dev->paintr)(greyscale?greyof(p->v):p->v, xmin, ymin, xmax, ymax); + recolor(p); /* paint it */ - if (dev->flush != NULL && nrays - lastflush >= WFLUSH) { - lastflush = nrays; - (*dev->flush)(); + if (dev->flush != NULL) { /* shall we check for input? */ + static RNUMBER lastflush = 0; + RNUMBER counter = raynum; + int flushintvl; + if (nproc == 1) { + counter = nrays; + flushintvl = WFLUSH1; + } else if (ambounce == 0) + flushintvl = nproc*WFLUSH; + else if (niflush < WFLUSH) + flushintvl = nproc*niflush/(ambounce+1); + else + flushintvl = nproc*WFLUSH/(ambounce+1); + if (lastflush > counter) + lastflush = 0; /* counter wrapped */ + + if (counter - lastflush >= flushintvl) { + lastflush = counter; + (*dev->flush)(); + niflush++; + } } + return(1); } -newimage() /* start a new image */ +int +waitrays(void) /* finish up pending rays */ { + int nwaited = 0; + int rval; + RAY raydone; + + if (nproc <= 1) /* immediate mode? */ + return(0); + while ((rval = ray_presult(&raydone, 0)) > 0) { + PNODE *p = (PNODE *)raydone.rno; + copycolor(p->v, raydone.rcol); + scalecolor(p->v, exposure); + recolor(p); + nwaited++; + } + if (rval < 0) + return(-1); + return(nwaited); +} + + +void +newimage( /* start a new image */ + char *s +) +{ + extern int ray_pnprocs; + int newnp; + /* change in nproc? */ + if (s != NULL && sscanf(s, "%d", &newnp) == 1 && + (newnp > 0) & (newnp != nproc)) { + if (!newparam) { + if (newnp == 1) + ray_pclose(0); + else if (newnp < ray_pnprocs) + ray_pclose(ray_pnprocs - newnp); + else + ray_popen(newnp - ray_pnprocs); + } + nproc = newnp; + } /* free old image */ freepkids(&ptrunk); - /* save reserve memory */ - fillreserves(); /* compute resolution */ hresolu = dev->xsiz; vresolu = dev->ysiz; normaspect(viewaspect(&ourview), &dev->pixaspect, &hresolu, &vresolu); - pframe.l = pframe.d = 0; - pframe.r = hresolu; pframe.u = vresolu; + ptrunk.xmin = ptrunk.ymin = pframe.l = pframe.d = 0; + ptrunk.xmax = pframe.r = hresolu; + ptrunk.ymax = pframe.u = vresolu; pdepth = 0; /* clear device */ (*dev->clear)(hresolu, vresolu); - /* get first value */ - paint(&ptrunk, 0, 0, hresolu, vresolu); + + if (newparam) { /* (re)start rendering procs */ + if (ray_pnprocs > 0) + ray_pclose(0); + if (nproc > 1) + ray_popen(nproc); + newparam = 0; + } + niflush = 0; /* get first value */ + paint(&ptrunk); } -redraw() /* redraw the image */ +void +redraw(void) /* redraw the image */ { (*dev->clear)(hresolu, vresolu); (*dev->comout)("redrawing...\n"); @@ -214,80 +315,81 @@ redraw() /* redraw the image */ } -repaint(xmin, ymin, xmax, ymax) /* repaint a region */ -int xmin, ymin, xmax, ymax; +void +repaint( /* repaint a region */ + int xmin, + int ymin, + int xmax, + int ymax +) { RECT reg; reg.l = xmin; reg.r = xmax; reg.d = ymin; reg.u = ymax; - paintrect(&ptrunk, 0, 0, hresolu, vresolu, ®); + paintrect(&ptrunk, ®); } -paintrect(p, xmin, ymin, xmax, ymax, r) /* paint picture rectangle */ -register PNODE *p; -int xmin, ymin, xmax, ymax; -register RECT *r; +void +paintrect( /* paint picture rectangle */ + PNODE *p, + RECT *r +) { int mx, my; - if (xmax - xmin <= 0 || ymax - ymin <= 0) + if (p->xmax - p->xmin <= 0 || p->ymax - p->ymin <= 0) return; if (p->kid == NULL) { (*dev->paintr)(greyscale?greyof(p->v):p->v, - xmin, ymin, xmax, ymax); /* do this */ + p->xmin, p->ymin, p->xmax, p->ymax); /* do this */ return; } - mx = (xmin + xmax) >> 1; /* do kids */ - my = (ymin + ymax) >> 1; + mx = (p->xmin + p->xmax) >> 1; /* do kids */ + my = (p->ymin + p->ymax) >> 1; if (mx > r->l) { if (my > r->d) - paintrect(p->kid+DL, xmin, ymin, mx, my, r); + paintrect(p->kid+DL, r); if (my < r->u) - paintrect(p->kid+UL, xmin, my, mx, ymax, r); + paintrect(p->kid+UL, r); } if (mx < r->r) { if (my > r->d) - paintrect(p->kid+DR, mx, ymin, xmax, my, r); + paintrect(p->kid+DR, r); if (my < r->u) - paintrect(p->kid+UR, mx, my, xmax, ymax, r); + paintrect(p->kid+UR, r); } } PNODE * -findrect(x, y, p, r, pd) /* find a rectangle */ -int x, y; -register PNODE *p; -register RECT *r; -int pd; +findrect( /* find a rectangle */ + int x, + int y, + PNODE *p, + int pd +) { int mx, my; while (p->kid != NULL && pd--) { - mx = (r->l + r->r) >> 1; - my = (r->d + r->u) >> 1; + mx = (p->xmin + p->xmax) >> 1; + my = (p->ymin + p->ymax) >> 1; if (x < mx) { - r->r = mx; if (y < my) { - r->u = my; p = p->kid+DL; } else { - r->d = my; p = p->kid+UL; } } else { - r->l = mx; if (y < my) { - r->u = my; p = p->kid+DR; } else { - r->d = my; p = p->kid+UR; } } @@ -296,10 +398,36 @@ int pd; } -scalepict(p, sf) /* scale picture values */ -register PNODE *p; -double sf; +void +compavg( /* recompute averages */ + PNODE *p +) { + int i, navg; + + if (p->kid == NULL) + return; + + setcolor(p->v, .0, .0, .0); + navg = 0; + for (i = 0; i < 4; i++) { + if (p->kid[i].xmin >= p->kid[i].xmax) continue; + if (p->kid[i].ymin >= p->kid[i].ymax) continue; + compavg(p->kid+i); + addcolor(p->v, p->kid[i].v); + navg++; + } + if (navg > 1) + scalecolor(p->v, 1./navg); +} + + +void +scalepict( /* scale picture values */ + PNODE *p, + double sf +) +{ scalecolor(p->v, sf); /* do this node */ if (p->kid == NULL) @@ -312,13 +440,16 @@ double sf; } -getpictcolrs(yoff, scan, p, xsiz, ysiz) /* get scanline from picture */ -int yoff; -register COLR *scan; -register PNODE *p; -int xsiz, ysiz; +void +getpictcolrs( /* get scanline from picture */ + int yoff, + COLR *scan, + PNODE *p, + int xsiz, + int ysiz +) { - register int mx; + int mx; int my; if (p->kid == NULL) { /* do this node */ @@ -342,72 +473,76 @@ int xsiz, ysiz; } -pcopy(p1, p2) /* copy paint node p1 into p2 */ -register PNODE *p1, *p2; +void +freepkids( /* free pnode's children */ + PNODE *p +) { - copycolor(p2->v, p1->v); - p2->x = p1->x; - p2->y = p1->y; -} - - -freepkids(p) /* free pnode's children */ -register PNODE *p; -{ if (p->kid == NULL) return; freepkids(p->kid+DL); freepkids(p->kid+DR); freepkids(p->kid+UL); freepkids(p->kid+UR); - free((char *)p->kid); + free((void *)p->kid); p->kid = NULL; } -newview(vp) /* change viewing parameters */ -register VIEW *vp; +void +newview( /* change viewing parameters */ + VIEW *vp +) { char *err; if ((err = setview(vp)) != NULL) { sprintf(errmsg, "view not set - %s", err); error(COMMAND, errmsg); - } else if (bcmp((char *)vp, (char *)&ourview, sizeof(VIEW))) { - copystruct(&oldview, &ourview); - copystruct(&ourview, vp); - newimage(); + } else if (memcmp((char *)vp, (char *)&ourview, sizeof(VIEW))) { + oldview = ourview; + ourview = *vp; + newimage(NULL); } } -moveview(angle, elev, mag, vc) /* move viewpoint */ -double angle, elev, mag; -FVECT vc; +void +moveview( /* move viewpoint */ + double angle, + double elev, + double mag, + FVECT vc +) { double d; FVECT v1; - VIEW nv; - register int i; + VIEW nv = ourview; + int i; - VCOPY(nv.vup, ourview.vup); - nv.hoff = ourview.hoff; nv.voff = ourview.voff; spinvector(nv.vdir, ourview.vdir, ourview.vup, angle*(PI/180.)); if (elev != 0.0) { fcross(v1, ourview.vup, nv.vdir); normalize(v1); spinvector(nv.vdir, nv.vdir, v1, elev*(PI/180.)); } - if ((nv.type = ourview.type) == VT_PAR) { - nv.horiz = ourview.horiz / mag; - nv.vert = ourview.vert / mag; + if (nv.type == VT_PAR) { + nv.horiz /= mag; + nv.vert /= mag; d = 0.0; /* don't move closer */ for (i = 0; i < 3; i++) d += (vc[i] - ourview.vp[i])*ourview.vdir[i]; } else { - nv.horiz = ourview.horiz; - nv.vert = ourview.vert; d = sqrt(dist2(ourview.vp, vc)) / mag; + if (nv.vfore > FTINY) { + nv.vfore += d - d*mag; + if (nv.vfore < 0.0) nv.vfore = 0.0; + } + if (nv.vaft > FTINY) { + nv.vaft += d - d*mag; + if (nv.vaft <= nv.vfore) nv.vaft = 0.0; + } + nv.vdist /= mag; } for (i = 0; i < 3; i++) nv.vp[i] = vc[i] - d*nv.vdir[i]; @@ -415,15 +550,54 @@ FVECT vc; } -zoomview(vp, zf) /* zoom in our out */ -register VIEW *vp; -double zf; +void +pcopy( /* copy paint node p1 into p2 */ + PNODE *p1, + PNODE *p2 +) { + copycolor(p2->v, p1->v); + p2->x = p1->x; + p2->y = p1->y; +} + + +void +zoomview( /* zoom in or out */ + VIEW *vp, + double zf +) +{ switch (vp->type) { case VT_PAR: /* parallel view */ + vp->horiz /= zf; + vp->vert /= zf; + return; case VT_ANG: /* angular fisheye */ vp->horiz /= zf; + if (vp->horiz > 360.) + vp->horiz = 360.; vp->vert /= zf; + if (vp->vert > 360.) + vp->vert = 360.; + return; + case VT_PLS: /* planisphere fisheye */ + vp->horiz = sin((PI/180./2.)*vp->horiz) / + (1.0 + cos((PI/180./2.)*vp->horiz)) / zf; + vp->horiz *= vp->horiz; + vp->horiz = (2.*180./PI)*acos((1. - vp->horiz) / + (1. + vp->horiz)); + vp->vert = sin((PI/180./2.)*vp->vert) / + (1.0 + cos((PI/180./2.)*vp->vert)) / zf; + vp->vert *= vp->vert; + vp->vert = (2.*180./PI)*acos((1. - vp->vert) / + (1. + vp->vert)); + return; + case VT_CYL: /* cylindrical panorama */ + vp->horiz /= zf; + if (vp->horiz > 360.) + vp->horiz = 360.; + vp->vert = atan(tan(vp->vert*(PI/180./2.))/zf) / (PI/180./2.); return; case VT_PER: /* perspective view */ vp->horiz = atan(tan(vp->horiz*(PI/180./2.))/zf) /