Пример #1
0
int
m_aniso(			/* anisotropic material */
	register OBJREC	*o
)
{
	register MATREC	*m;
					/* check arguments */
	if (o->oargs.nfargs < (o->otype == MAT_TRANS2 ? 8 : 6))
		objerror(o, USER, "bad # of real arguments");
					/* allocate/insert material */
	m = newmaterial(o->oname);
					/* assign parameters */
	setcolor(m->u.m.ambdiff, o->oargs.farg[0],
			o->oargs.farg[1], o->oargs.farg[2]);
	if ((m->type = o->otype) == MAT_METAL2)
		copycolor(m->u.m.specular, m->u.m.ambdiff);
	else
		setcolor(m->u.m.specular, 1., 1., 1.);
	scalecolor(m->u.m.specular, o->oargs.farg[3]);
	scalecolor(m->u.m.ambdiff, 1.-o->oargs.farg[3]);
	if (m->type == MAT_TRANS2) {
		scalecolor(m->u.m.specular, 1.-o->oargs.farg[6]);
		scalecolor(m->u.m.ambdiff, 1.-o->oargs.farg[6]);
	}
	if (o->oargs.farg[4]*o->oargs.farg[5] <= FTINY*FTINY)
		m->u.m.specexp = MAXSPECEXP;
	else
		m->u.m.specexp = 2./(o->oargs.farg[4]*o->oargs.farg[5]);
	if (m->u.m.specexp > MAXSPECEXP)
		m->u.m.specexp = MAXSPECEXP;
	return(0);
}
Пример #2
0
static void
dirashik(		/* compute source contribution */
	COLOR  cval,		/* returned coefficient */
	void  *nnp,		/* material data */
	FVECT  ldir,		/* light source direction */
	double  omega		/* light source size */
)
{
	ASHIKDAT *np = nnp;
	double  ldot;
	double  dtmp, dtmp1, dtmp2;
	FVECT  h;
	COLOR  ctmp;

	setcolor(cval, 0.0, 0.0, 0.0);

	ldot = DOT(np->pnorm, ldir);

	if (ldot < 0.0)
		return;		/* wrong side */

	/*
	 *  Compute and add diffuse reflected component to returned
	 *  color.
	 */
	copycolor(ctmp, np->mcolor);
	dtmp = ldot * omega * (1.0/PI) * (1. - schlick_fres(ldot));
	scalecolor(ctmp, dtmp);		
	addcolor(cval, ctmp);

	if ((np->specfl & (SPA_REFL|SPA_BADU)) != SPA_REFL)
		return;
	/*
	 *  Compute specular reflection coefficient
	 */
					/* half vector */
	VSUB(h, ldir, np->rp->rdir);
	normalize(h);
					/* ellipse */
	dtmp1 = DOT(np->u, h);
	dtmp1 *= dtmp1 * np->u_power;
	dtmp2 = DOT(np->v, h);
	dtmp2 *= dtmp2 * np->v_power;
					/* Ashikhmin-Shirley model*/
	dtmp = DOT(np->pnorm, h);
	dtmp = pow(dtmp, (dtmp1+dtmp2)/(1.-dtmp*dtmp));
	dtmp *= sqrt((np->u_power+1.)*(np->v_power+1.));
	dtmp /= 8.*PI * DOT(ldir,h) * MAX(ldot,np->pdot);
					/* worth using? */
	if (dtmp > FTINY) {
		copycolor(ctmp, np->scolor);
		dtmp *= ldot * omega;
		scalecolor(ctmp, dtmp);
		addcolor(cval, ctmp);
	}
}
Пример #3
0
extern void
scotscan(		/* apply scotopic color sensitivity loss */
	COLOR	*scan,
	int	xres
)
{
	COLOR	ctmp;
	double	incolor, b, Lw;
	register int	i;

	for (i = 0; i < xres; i++) {
		Lw = plum(scan[i]);
		if (Lw >= TopMesopic)
			incolor = 1.;
		else if (Lw <= BotMesopic)
			incolor = 0.;
		else
			incolor = (Lw - BotMesopic) /
					(TopMesopic - BotMesopic);
		if (incolor < 1.-FTINY) {
			b = (1.-incolor)*slum(scan[i])*inpexp/SWNORM;
			if (lumf == rgblum) b /= WHTEFFICACY;
			setcolor(ctmp, b, b, b);
			if (incolor <= FTINY)
				setcolor(scan[i], 0., 0., 0.);
			else
				scalecolor(scan[i], incolor);
			addcolor(scan[i], ctmp);
		}
	}
}
Пример #4
0
extern void
extambient(		/* extrapolate value at pv, nv */
	COLOR  cr,
	AMBVAL	 *ap,
	FVECT  pv,
	FVECT  nv
)
{
	FVECT  v1;
	int  i;
	double	d;

	d = 1.0;			/* zeroeth order */
					/* gradient due to translation */
	for (i = 0; i < 3; i++)
		d += ap->gpos[i]*(pv[i]-ap->pos[i]);
					/* gradient due to rotation */
	VCROSS(v1, ap->dir, nv);
	d += DOT(ap->gdir, v1);
	if (d <= 0.0) {
		setcolor(cr, 0.0, 0.0, 0.0);
		return;
	}
	copycolor(cr, ap->val);
	scalecolor(cr, d);
}
Пример #5
0
static void
init(void)				/* initialize */
{
	double	quad[4][2];
	register int	i;
					/* make coordinate transformation */
	quad[0][0] = bounds[0][0];
	quad[0][1] = bounds[0][1];
	quad[1][0] = bounds[1][0];
	quad[1][1] = bounds[1][1];
	quad[2][0] = bounds[3][0];
	quad[2][1] = bounds[3][1];
	quad[3][0] = bounds[2][0];
	quad[3][1] = bounds[2][1];

	if (pmap_quad_rect(0., 0., 6., 4., quad, imgxfm) == PMAP_BAD) {
		fprintf(stderr, "%s: bad chart boundaries\n", progname);
		exit(1);
	}
					/* map MacBeth colors to RGB space */
	for (i = 0; i < 24; i++) {
		xyY2RGB(mbRGB[i], mbxyY[i]);
		scalecolor(mbRGB[i], irrad);
	}
}
Пример #6
0
static int
checkhead(				/* deal with line from header */
	char	*line,
	void	*p
)
{
	char	fmt[32];
	double	d;
	COLOR	ctmp;

	if (formatval(fmt, line)) {
		if (!strcmp(fmt, CIEFMT))
			mybright = &xyz_bright;
		else if (!strcmp(fmt, COLRFMT))
			mybright = &rgb_bright;
		else
			wrongformat++;
	} else if (original && isexpos(line)) {
		d = 1.0/exposval(line);
		scalecolor(exposure, d);
		doexposure++;
	} else if (original && iscolcor(line)) {
		colcorval(ctmp, line);
		setcolor(exposure, colval(exposure,RED)/colval(ctmp,RED),
				colval(exposure,GRN)/colval(ctmp,GRN),
				colval(exposure,BLU)/colval(ctmp,BLU));
		doexposure++;
	} else if (header)
		fputs(line, stdout);
	return(0);
}
Пример #7
0
static void
ppm2ra2(	/* convert 2-byte Pixmap to Radiance picture */
	colorscanf_t *getscan
)
{
	COLOR	*scanout;
	double	mult;
	int	y;
	register int	x;
						/* allocate scanline */
	scanout = (COLOR *)malloc(xmax*sizeof(COLOR));
	if (scanout == NULL)
		quiterr("out of memory in ppm2ra2");
	if (bradj)
		mult = pow(2., (double)bradj);
						/* convert image */
	for (y = ymax-1; y >= 0; y--) {
		if ((*getscan)(scanout, xmax, stdin) < 0)
			quiterr("error reading Pixmap");
		for (x = (gamcor>1.01)|(gamcor<0.99)?xmax:0; x--; ) {
			colval(scanout[x],RED) =
					pow(colval(scanout[x],RED), gamcor);
			colval(scanout[x],GRN) =
					pow(colval(scanout[x],GRN), gamcor);
			colval(scanout[x],BLU) =
					pow(colval(scanout[x],BLU), gamcor);
		}
		for (x = bradj?xmax:0; x--; )
			scalecolor(scanout[x], mult);
		if (fwritescan(scanout, xmax, stdout) < 0)
			quiterr("error writing Radiance picture");
	}
						/* free scanline */
	free((void *)scanout);
}
Пример #8
0
static AMBHEMI *
samp_hemi(				/* sample indirect hemisphere */
	COLOR	rcol,
	RAY	*r,
	double	wt
)
{
	AMBHEMI	*hp;
	double	d;
	int	n, i, j;
					/* insignificance check */
	if (bright(rcol) <= FTINY)
		return(NULL);
					/* set number of divisions */
	if (ambacc <= FTINY &&
			wt > (d = 0.8*intens(rcol)*r->rweight/(ambdiv*minweight)))
		wt = d;			/* avoid ray termination */
	n = sqrt(ambdiv * wt) + 0.5;
	i = 1 + 5*(ambacc > FTINY);	/* minimum number of samples */
	if (n < i)
		n = i;
					/* allocate sampling array */
	hp = (AMBHEMI *)malloc(sizeof(AMBHEMI) + sizeof(AMBSAMP)*(n*n - 1));
	if (hp == NULL)
		error(SYSTEM, "out of memory in samp_hemi");
	hp->rp = r;
	hp->ns = n;
	hp->acol[RED] = hp->acol[GRN] = hp->acol[BLU] = 0.0;
	memset(hp->sa, 0, sizeof(AMBSAMP)*n*n);
	hp->sampOK = 0;
					/* assign coefficient */
	copycolor(hp->acoef, rcol);
	d = 1.0/(n*n);
	scalecolor(hp->acoef, d);
					/* make tangent plane axes */
	if (!getperpendicular(hp->ux, r->ron, 1))
		error(CONSISTENCY, "bad ray direction in samp_hemi");
	VCROSS(hp->uy, r->ron, hp->ux);
					/* sample divisions */
	for (i = hp->ns; i--; )
	    for (j = hp->ns; j--; )
		hp->sampOK += ambsample(hp, i, j, 0);
	copycolor(rcol, hp->acol);
	if (!hp->sampOK) {		/* utter failure? */
		free(hp);
		return(NULL);
	}
	if (hp->sampOK < hp->ns*hp->ns) {
		hp->sampOK *= -1;	/* soft failure */
		return(hp);
	}
	if (hp->sampOK < 64)
		return(hp);		/* insufficient for super-sampling */
	n = ambssamp*wt + 0.5;
	if (n > 8) {			/* perform super-sampling? */
		ambsupersamp(hp, n);
		copycolor(rcol, hp->acol);
	}
	return(hp);			/* all is well */
}
Пример #9
0
/* Put out ray contribution to file */
static void
put_contrib(const DCOLOR cnt, FILE *fout)
{
	double	sf = 1;
	COLOR	fv;
	COLR	cv;

	if (accumulate > 1)
		sf = 1./(double)accumulate;
	switch (outfmt) {
	case 'a':
		if (accumulate > 1)
			fprintf(fout, "%.6e\t%.6e\t%.6e\t",
					sf*cnt[0], sf*cnt[1], sf*cnt[2]);
		else
			fprintf(fout, "%.6e\t%.6e\t%.6e\t",
					cnt[0], cnt[1], cnt[2]);
		break;
	case 'f':
		if (accumulate > 1) {
			copycolor(fv, cnt);
			scalecolor(fv, sf);
		} else
			copycolor(fv, cnt);
		fwrite(fv, sizeof(float), 3, fout);
		break;
	case 'd':
		if (accumulate > 1) {
			DCOLOR	dv;
			copycolor(dv, cnt);
			scalecolor(dv, sf);
			fwrite(dv, sizeof(double), 3, fout);
		} else
			fwrite(cnt, sizeof(double), 3, fout);
		break;
	case 'c':
		if (accumulate > 1)
			setcolr(cv, sf*cnt[0], sf*cnt[1], sf*cnt[2]);
		else
			setcolr(cv, cnt[0], cnt[1], cnt[2]);
		fwrite(cv, sizeof(cv), 1, fout);
		break;
	default:
		error(INTERNAL, "botched output format");
	}
}
Пример #10
0
static void
sfscan(			/* apply scalefactor to scanline */
	register COLOR	*sl,
	int	len,
	double	sf
)
{
	while (len--) {
		scalecolor(sl[0], sf);
		sl++;
	}
}
Пример #11
0
extern int
raymixture(		/* mix modifiers */
	RAY  *r,
	OBJECT  fore,
	OBJECT  back,
	double  coef
)
{
	RAY  fr, br;
	int  foremat, backmat;
	int  i;
					/* bound coefficient */
	if (coef > 1.0)
		coef = 1.0;
	else if (coef < 0.0)
		coef = 0.0;
					/* compute foreground and background */
	foremat = backmat = 0;
					/* foreground */
	fr = *r;
	if (coef > FTINY) {
		fr.rweight *= coef;
		scalecolor(fr.rcoef, coef);
		foremat = rayshade(&fr, fore);
	}
					/* background */
	br = *r;
	if (coef < 1.0-FTINY) {
		br.rweight *= 1.0-coef;
		scalecolor(br.rcoef, 1.0-coef);
		backmat = rayshade(&br, back);
	}
					/* check for transparency */
	if (backmat ^ foremat) {
		if (backmat && coef > FTINY)
			raytrans(&fr);
		else if (foremat && coef < 1.0-FTINY)
			raytrans(&br);
	}
					/* mix perturbations */
	for (i = 0; i < 3; i++)
		r->pert[i] = coef*fr.pert[i] + (1.0-coef)*br.pert[i];
					/* mix pattern colors */
	scalecolor(fr.pcol, coef);
	scalecolor(br.pcol, 1.0-coef);
	copycolor(r->pcol, fr.pcol);
	addcolor(r->pcol, br.pcol);
					/* return value tells if material */
	if (!foremat & !backmat)
		return(0);
					/* mix returned ray values */
	scalecolor(fr.rcol, coef);
	scalecolor(br.rcol, 1.0-coef);
	copycolor(r->rcol, fr.rcol);
	addcolor(r->rcol, br.rcol);
	r->rt = bright(fr.rcol) > bright(br.rcol) ? fr.rt : br.rt;
	return(1);
}
Пример #12
0
extern void
dogauss(		/* gaussian filter */
	COLOR  csum,
	int  xcent,
	int  ycent,
	int  c,
	int  r
)
{
	double  dy, dx, weight, wsum;
	COLOR  ctmp;
	int  y;
	register int  x, offs;
	register COLOR	*scan;

	wsum = FTINY;
	setcolor(csum, 0.0, 0.0, 0.0);
	for (y = ycent-yrad; y <= ycent+yrad; y++) {
		if (y < 0) continue;
		if (y >= yres) break;
		dy = (y_r*(y+.5) - (r+.5))/rad;
		scan = scanin[y%barsize];
		for (x = xcent-xrad; x <= xcent+xrad; x++) {
			offs = x < 0 ? xres : x >= xres ? -xres : 0;
			if (offs && !wrapfilt)
				continue;
			dx = (x_c*(x+.5) - (c+.5))/rad;
			weight = lookgauss(dx*dx + dy*dy);
			wsum += weight;
			copycolor(ctmp, scan[x+offs]);
			scalecolor(ctmp, weight);
			addcolor(csum, ctmp);
		}
	}
	weight = 1.0/wsum;
	scalecolor(csum, weight);
}
Пример #13
0
extern void
pass2init(void)			/* prepare for final pass */
{
	if (!npix) {
		fprintf(stderr, "%s: picture too dark or too bright\n",
				progname);
		quit(1);
	}
	avgbrt /= (double)npix;

	scalecolor(exposure,  AVGLVL/avgbrt);
	
	sprdfact = spread / (hotlvl * (*ourbright)(exposure))
			* ((double)xres*xres + (double)yres*yres) / 4.0;
}
Пример #14
0
void
scalepict(				/* scale picture values */
	PNODE  *p,
	double  sf
)
{
	scalecolor(p->v, sf);		/* do this node */

	if (p->kid == NULL)
		return;
					/* do children */
	scalepict(p->kid+DL, sf);
	scalepict(p->kid+DR, sf);
	scalepict(p->kid+UL, sf);
	scalepict(p->kid+UR, sf);
}
Пример #15
0
int
waitrays(void)					/* finish up pending rays */
{
	int	nwaited = 0;
	int	rval;
	RAY	raydone;

	if (!ray_pnprocs)			/* 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);
}
Пример #16
0
static void
getpicture(void)				/* load in picture colors */
{
	COLR	*scanln;
	COLOR	pval;
	int	ccount[24];
	double	d;
	int	y, i;
	register int	x;

	scanln = (COLR *)malloc(xmax*sizeof(COLR));
	if (scanln == NULL) {
		perror(progname);
		exit(1);
	}
	for (i = 0; i < 24; i++) {
		setcolor(inpRGB[i], 0., 0., 0.);
		ccount[i] = 0;
	}
	for (y = ymax-1; y >= 0; y--) {
		if (freadcolrs(scanln, xmax, stdin) < 0) {
			fprintf(stderr, "%s: error reading input picture\n",
					progname);
			exit(1);
		}
		for (x = 0; x < xmax; x++)
			if (chartndx(x, y, &i) == RG_CENT) {
				colr_color(pval, scanln[x]);
				addcolor(inpRGB[i], pval);
				ccount[i]++;
			}
	}
	for (i = 0; i < 24; i++) {		/* compute averages */
		if (ccount[i] == 0)
			continue;
		d = 1./ccount[i];
		scalecolor(inpRGB[i], d);
		inpflags |= 1L<<i;
	}
	free((void *)scanln);
}
Пример #17
0
extern void
mapscan(		/* apply tone mapping operator to scanline */
	COLOR	*scan,
	int	xres
)
{
	double	mult, Lw, b;
	register int	x;

	for (x = 0; x < xres; x++) {
		Lw = plum(scan[x]);
		if (Lw < LMIN) {
			setcolor(scan[x], 0., 0., 0.);
			continue;
		}
		b = BLw(Lw);		/* apply brightness mapping */
		mult = (Lb(b) - ldmin)/(ldmax - ldmin)/(Lw*inpexp);
		if (lumf == rgblum) mult *= WHTEFFICACY;
		scalecolor(scan[x], mult);
	}
}
Пример #18
0
extern void
dobox(			/* simple box filter */
	COLOR  csum,
	int  xcent,
	int  ycent,
	int  c,
	int  r
)
{
	int  wsum;
	double  d;
	int  y;
	register int  x, offs;
	register COLOR	*scan;
	
	wsum = 0;
	setcolor(csum, 0.0, 0.0, 0.0);
	for (y = ycent+1-ybrad; y <= ycent+ybrad; y++) {
		if (y < 0) continue;
		if (y >= yres) break;
		d = y_r < 1.0 ? y_r*y - (r+.5) : (double)(y - ycent);
		if (d < -0.5) continue;
		if (d >= 0.5) break;
		scan = scanin[y%barsize];
		for (x = xcent+1-xbrad; x <= xcent+xbrad; x++) {
			offs = x < 0 ? xres : x >= xres ? -xres : 0;
			if (offs && !wrapfilt)
				continue;
			d = x_c < 1.0 ? x_c*x - (c+.5) : (double)(x - xcent);
			if (d < -0.5) continue;
			if (d >= 0.5) break;
			wsum++;
			addcolor(csum, scan[x+offs]);
		}
	}
	if (wsum > 1) {
		d = 1.0/wsum;
		scalecolor(csum, d);
	}
}
Пример #19
0
extern int
p_bfunc(			/* compute brightness pattern */
    OBJREC  *m,
    RAY  *r
)
{
    double  bval;
    register MFUNC  *mf;

    if (m->oargs.nsargs < 2)
        objerror(m, USER, "bad # arguments");
    mf = getfunc(m, 1, 0x1, 0);
    setfunc(m, r);
    errno = 0;
    bval = evalue(mf->ep[0]);
    if (errno == EDOM || errno == ERANGE) {
        objerror(m, WARNING, "compute error");
        return(0);
    }
    scalecolor(r->pcol, bval);
    return(0);
}
Пример #20
0
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);
}
Пример #21
0
extern double
makeambient(		/* make a new ambient value for storage */
	COLOR  acol,
	RAY  *r,
	FVECT  rn,
	int  al
)
{
	AMBVAL	amb;
	FVECT	gp, gd;
	int	i;

	amb.weight = 1.0;			/* compute weight */
	for (i = al; i-- > 0; )
		amb.weight *= AVGREFL;
	if (r->rweight < 0.1*amb.weight)	/* heuristic override */
		amb.weight = 1.25*r->rweight;
	setcolor(acol, AVGREFL, AVGREFL, AVGREFL);
						/* compute ambient */
	amb.rad = doambient(acol, r, amb.weight, gp, gd);
	if (amb.rad <= FTINY) {
		setcolor(acol, 0.0, 0.0, 0.0);
		return(0.0);
	}
	scalecolor(acol, 1./AVGREFL);		/* undo assumed reflectance */
						/* store value */
	VCOPY(amb.pos, r->rop);
	VCOPY(amb.dir, r->ron);
	amb.lvl = al;
	copycolor(amb.val, acol);
	VCOPY(amb.gpos, gp);
	VCOPY(amb.gdir, gd);
						/* insert into tree */
	avsave(&amb);				/* and save to file */
	if (rn != r->ron)
		extambient(acol, &amb, r->rop, rn);	/* texture */
	return(amb.rad);
}
Пример #22
0
static void
starpoint(		/* pixel is on the star's point */
	COLOR  fcol,
	int  x,
	int  y,
	register HOTPIX	 *hp
)
{
	COLOR  ctmp;
	double	d2;
	
	d2 = (double)(x - hp->x)*(x - hp->x) + (double)(y - hp->y)*(y - hp->y);
	if (d2 > sprdfact) {
		d2 = sprdfact / d2;
		if (d2 < FTINY)
			return;
		copycolor(ctmp, hp->val);
		scalecolor(ctmp, d2);
		addcolor(fcol, ctmp);
	} else if (d2 > FTINY) {
		addcolor(fcol, hp->val);
	}
}
Пример #23
0
static int
headline(			/* check header line & echo if requested */
	char	*s,
	void	*p
)
{
	char	fmt[32];
	double	d;
	COLOR	ctmp;

	if (isheadid(s))			/* header id */
		return(0);	/* don't echo */
	if (formatval(fmt, s)) {		/* check format */
		if (globmatch(ourfmt, fmt)) {
			wrongformat = 0;
			strcpy(ourfmt, fmt);
		} else
			wrongformat = globmatch(PICFMT, fmt) ? 1 : -1;
		return(0);	/* don't echo */
	}
	if (isexpos(s)) {			/* exposure */
		d = exposval(s);
		scalecolor(input[nfiles].expos, d);
	} else if (iscolcor(s)) {		/* color correction */
		colcorval(ctmp, s);
		multcolor(input[nfiles].expos, ctmp);
	} else if (isaspect(s))
		input[nfiles].pa *= aspectval(s);
	else if (isview(s) && sscanview(&input[nfiles].vw, s) > 0)
		gotview++;

	if (echoheader) {			/* echo line */
		putchar('\t');
		return(fputs(s, stdout));
	}
	return(0);
}
Пример #24
0
static void
sumans(		/* sum input pixel to output */
	int  px,
	int  py,
	int  rcent,
	int  ccent,
	double  m
)
{
	double  dy2, dx;
	COLOR  pval, ctmp;
	int  ksiz, r, offs;
	double  pc, pr, norm;
	register int  i, c;
	register COLOR	*scan;
	/*
	 * This normalization method fails at the picture borders because
	 * a different number of input pixels contribute there.
	 */
	scan = scanin[py%barsize] + (px < 0 ? xres : px >= xres ? -xres : 0);
	copycolor(pval, scan[px]);
	pc = x_c*(px+.5);
	pr = y_r*(py+.5);
	ksiz = CHECKRAD*m*rad + 1;
	if (ksiz > orad) ksiz = orad;
						/* compute normalization */
	norm = 0.0;
	i = 0;
	for (r = rcent-ksiz; r <= rcent+ksiz; r++) {
		if (r < 0) continue;
		if (r >= nrows) break;
		dy2 = (pr - (r+.5))/(m*rad);
		dy2 *= dy2;
		for (c = ccent-ksiz; c <= ccent+ksiz; c++) {
			if (!wrapfilt) {
				if (c < 0) continue;
				if (c >= ncols) break;
			}
			dx = (pc - (c+.5))/(m*rad);
			norm += warr[i++] = lookgauss(dx*dx + dy2);
		}
	}
	norm = 1.0/norm;
	if (x_c < 1.0) norm *= x_c;
	if (y_r < 1.0) norm *= y_r;
						/* sum pixels */
	i = 0;
	for (r = rcent-ksiz; r <= rcent+ksiz; r++) {
		if (r < 0) continue;
		if (r >= nrows) break;
		scan = scoutbar[r%obarsize];
		for (c = ccent-ksiz; c <= ccent+ksiz; c++) {
			offs = c < 0 ? ncols : c >= ncols ? -ncols : 0;
			if (offs && !wrapfilt)
				continue;
			copycolor(ctmp, pval);
			dx = norm*warr[i++];
			scalecolor(ctmp, dx);
			addcolor(scan[c+offs], ctmp);
		}
	}
}
Пример #25
0
void volumePhotonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
/* Photon volume density estimate. Returns irradiance at ray -> rop. */
{
   unsigned                      i;
   float                         r2, gecc2, ph;
   COLOR                         flux;
   Photon                        *photon;
   const PhotonSearchQueueNode   *sqn;

   setcolor(irrad, 0, 0, 0);
   
   if (!pmap -> maxGather) 
      return;
      
   findPhotons(pmap, ray);
   
   /* Need at least 2 photons */
   if (pmap -> squeue.tail < 2) 
      return;

#if 0      
   /* Volume biascomp disabled (probably redundant) */
   if (pmap -> minGather == pmap -> maxGather)
#endif   
   {
      /* No bias compensation. Just do a plain vanilla estimate */
      gecc2 = ray -> gecc * ray -> gecc;
      sqn = pmap -> squeue.node + 1;
      
      /* Average radius^2 between furthest two photons to improve accuracy */      
      r2 = max(sqn -> dist2, (sqn + 1) -> dist2);
      r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2));
      
      /* Skip the extra photon */
      for (i = 1; i < pmap -> squeue.tail; i++, sqn++) {
         photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
         
         /* Compute phase function for inscattering from photon */
         if (gecc2 <= FTINY) 
            ph = 1;
         else {
            ph = DOT(ray -> rdir, photon -> norm) / 127;
            ph = 1 + gecc2 - 2 * ray -> gecc * ph;
            ph = (1 - gecc2) / (ph * sqrt(ph));
         }
         
         getPhotonFlux(photon, flux);
         scalecolor(flux, ph);
         addcolor(irrad, flux);
      }
      
      /* Divide by search volume 4 / 3 * PI * r^3 and phase function
         normalization factor 1 / (4 * PI) */
      scalecolor(irrad, 3 / (16 * PI * PI * r2 * sqrt(r2)));
      return;
   }
#if 0
   else 
      /* Apply bias compensation to density estimate */
      volumeBiasComp(pmap, ray, irrad);
#endif      
}
Пример #26
0
void photonDensity (PhotonMap *pmap, RAY *ray, COLOR irrad)
/* Photon density estimate. Returns irradiance at ray -> rop. */
{
   unsigned                      i;
   float                         r2;
   COLOR                         flux;
   Photon                        *photon;
   const PhotonSearchQueueNode   *sqn;
 
   setcolor(irrad, 0, 0, 0);

   if (!pmap -> maxGather) 
      return;
      
   /* Ignore sources */
   if (ray -> ro && islight(objptr(ray -> ro -> omod) -> otype)) 
      return;
         
   findPhotons(pmap, ray);
   
   /* Need at least 2 photons */
   if (pmap -> squeue.tail < 2) {
#ifdef PMAP_NONEFOUND   
      sprintf(errmsg, "no photons found on %s at (%.3f, %.3f, %.3f)", 
              ray -> ro ? ray -> ro -> oname : "<null>",
              ray -> rop [0], ray -> rop [1], ray -> rop [2]);
      error(WARNING, errmsg);
#endif      

      return;
   }

   if (pmap -> minGather == pmap -> maxGather) {
      /* No bias compensation. Just do a plain vanilla estimate */
      sqn = pmap -> squeue.node + 1;
      
      /* Average radius^2 between furthest two photons to improve accuracy */
      r2 = max(sqn -> dist2, (sqn + 1) -> dist2);
      r2 = 0.25 * (pmap -> maxDist2 + r2 + 2 * sqrt(pmap -> maxDist2 * r2));
      
      /* Skip the extra photon */
      for (i = 1 ; i < pmap -> squeue.tail; i++, sqn++) {
         photon = getNearestPhoton(&pmap -> squeue, sqn -> idx);
         getPhotonFlux(photon, flux);         
#ifdef PMAP_EPANECHNIKOV
         /* Apply Epanechnikov kernel to photon flux based on photon dist */
         scalecolor(flux, 2 * (1 - sqn -> dist2 / r2));
#endif   
         addcolor(irrad, flux);
      }
      
      /* Divide by search area PI * r^2, 1 / PI required as ambient 
         normalisation factor */         
      scalecolor(irrad, 1 / (PI * PI * r2)); 
      
      return;
   }
   else 
      /* Apply bias compensation to density estimate */
      biasComp(pmap, irrad);
}
Пример #27
0
static int
ambsample(				/* initial ambient division sample */
	AMBHEMI	*hp,
	int	i,
	int	j,
	int	n
)
{
	AMBSAMP	*ap = &ambsam(hp,i,j);
	RAY	ar;
	int	hlist[3], ii;
	double	spt[2], zd;
					/* generate hemispherical sample */
					/* ambient coefficient for weight */
	if (ambacc > FTINY)
		setcolor(ar.rcoef, AVGREFL, AVGREFL, AVGREFL);
	else
		copycolor(ar.rcoef, hp->acoef);
	if (rayorigin(&ar, AMBIENT, hp->rp, ar.rcoef) < 0)
		return(0);
	if (ambacc > FTINY) {
		multcolor(ar.rcoef, hp->acoef);
		scalecolor(ar.rcoef, 1./AVGREFL);
	}
	hlist[0] = hp->rp->rno;
	hlist[1] = j;
	hlist[2] = i;
	multisamp(spt, 2, urand(ilhash(hlist,3)+n));
resample:
	SDsquare2disk(spt, (j+spt[1])/hp->ns, (i+spt[0])/hp->ns);
	zd = sqrt(1. - spt[0]*spt[0] - spt[1]*spt[1]);
	for (ii = 3; ii--; )
		ar.rdir[ii] =	spt[0]*hp->ux[ii] +
				spt[1]*hp->uy[ii] +
				zd*hp->rp->ron[ii];
	checknorm(ar.rdir);
					/* avoid coincident samples */
	if (!n && ambcollision(hp, i, j, ar.rdir)) {
		spt[0] = frandom(); spt[1] = frandom();
		goto resample;		/* reject this sample */
	}
	dimlist[ndims++] = AI(hp,i,j) + 90171;
	rayvalue(&ar);			/* evaluate ray */
	ndims--;
	zd = raydistance(&ar);
	if (zd <= FTINY)
		return(0);		/* should never happen */
	multcolor(ar.rcol, ar.rcoef);	/* apply coefficient */
	if (zd*ap->d < 1.0)		/* new/closer distance? */
		ap->d = 1.0/zd;
	if (!n) {			/* record first vertex & value */
		if (zd > 10.0*thescene.cusize + 1000.)
			zd = 10.0*thescene.cusize + 1000.;
		VSUM(ap->p, ar.rorg, ar.rdir, zd);
		copycolor(ap->v, ar.rcol);
	} else {			/* else update recorded value */
		hp->acol[RED] -= colval(ap->v,RED);
		hp->acol[GRN] -= colval(ap->v,GRN);
		hp->acol[BLU] -= colval(ap->v,BLU);
		zd = 1.0/(double)(n+1);
		scalecolor(ar.rcol, zd);
		zd *= (double)n;
		scalecolor(ap->v, zd);
		addcolor(ap->v, ar.rcol);
	}
	addcolor(hp->acol, ap->v);	/* add to our sum */
	return(1);
}
Пример #28
0
int
main(
	int  argc,
	char  **argv
)
{
	double  d, expval = 1.0;
	int  i;

	progname = argv[0];
	mybright = &rgb_bright; /* default */

	for (i = 1; i < argc; i++)
		if (argv[i][0] == '-' || argv[i][0] == '+')
			switch (argv[i][1]) {
			case 'h':		/* header */
				header = argv[i][0] == '+';
				break;
			case 'H':		/* resolution string */
				resolution = argv[i][0] == '+';
				break;
			case 's':		/* skip bytes in header */
				skipbytes = atol(argv[++i]);
				break;
			case 'u':		/* unique values */
				uniq = argv[i][0] == '-';
				break;
			case 'o':		/* original values */
				original = argv[i][0] == '-';
				break;
			case 'g':		/* gamma correction */
				gamcor = atof(argv[i+1]);
				if (argv[i][0] == '+')
					gamcor = 1.0/gamcor;
				i++;
				break;
			case 'e':		/* exposure correction */
				d = atof(argv[i+1]);
				if (argv[i+1][0] == '-' || argv[i+1][0] == '+')
					d = pow(2.0, d);
				if (argv[i][0] == '-')
					expval *= d;
				scalecolor(exposure, d);
				doexposure++;
				i++;
				break;
			case 'R':		/* reverse byte sequence */
				if (argv[i][0] == '-') {
					ord[0]=BLU; ord[1]=GRN; ord[2]=RED;
				} else {
					ord[0]=RED; ord[1]=GRN; ord[2]=BLU;
				}
				break;
			case 'r':		/* reverse conversion */
				reverse = argv[i][0] == '-';
				break;
			case 'n':		/* non-interleaved RGB */
				interleave = argv[i][0] == '+';
				break;
			case 'b':		/* brightness values */
				putprim = argv[i][0] == '-' ? BRIGHT : ALL;
				break;
			case 'p':		/* primary controls */
				switch (argv[i][2]) {
				/* these two options affect -r conversion */
				case '\0':
					myprims[RED][CIEX] = atof(argv[++i]);
					myprims[RED][CIEY] = atof(argv[++i]);
					myprims[GRN][CIEX] = atof(argv[++i]);
					myprims[GRN][CIEY] = atof(argv[++i]);
					myprims[BLU][CIEX] = atof(argv[++i]);
					myprims[BLU][CIEY] = atof(argv[++i]);
					myprims[WHT][CIEX] = atof(argv[++i]);
					myprims[WHT][CIEY] = atof(argv[++i]);
					outprims = myprims;
					break;
				case 'x': case 'X': outprims = NULL; break;
				/* the following options affect +r only */
				case 'r': case 'R': putprim = RED; break;
				case 'g': case 'G': putprim = GRN; break;
				case 'b': case 'B': putprim = BLU; break;
				default: goto unkopt;
				}
				break;
			case 'd':		/* data only (no indices) */
				dataonly = argv[i][0] == '-';
				switch (argv[i][2]) {
				case '\0':
				case 'a':		/* ascii */
					format = 'a';
					fmtid = "ascii";
					break;
				case 'i':		/* integer */
					format = 'i';
					fmtid = "ascii";
					break;
				case 'b':		/* byte */
					dataonly = 1;
					format = 'b';
					fmtid = "byte";
					break;
				case 'W':		/* 16-bit swapped */
					swapbytes = 1;
				case 'w':		/* 16-bit */
					dataonly = 1;
					format = 'w';
					fmtid = "16-bit";
					break;
				case 'F':		/* swapped floats */
					swapbytes = 1;
				case 'f':		/* float */
					dataonly = 1;
					format = 'f';
					fmtid = "float";
					break;
				case 'D':		/* swapped doubles */
					swapbytes = 1;
				case 'd':		/* double */
					dataonly = 1;
					format = 'd';
					fmtid = "double";
					break;
				default:
					goto unkopt;
				}
				break;
			case 'x':		/* x resolution */
			case 'X':		/* x resolution */
				resolution = 0;
				if (argv[i][0] == '-')
					picres.rt |= XDECR;
				picres.xr = atoi(argv[++i]);
				break;
			case 'y':		/* y resolution */
			case 'Y':		/* y resolution */
				resolution = 0;
				if (argv[i][0] == '-')
					picres.rt |= YDECR;
				if (picres.xr == 0)
					picres.rt |= YMAJOR;
				picres.yr = atoi(argv[++i]);
				break;
			default:
unkopt:
				fprintf(stderr, "%s: unknown option: %s\n",
						progname, argv[i]);
				quit(1);
				break;
			}
		else
			break;
					/* recognize special formats */
	if (dataonly && format == 'b') {
		if (putprim == ALL)
			fmtid = "24-bit_rgb";
		else
			fmtid = "8-bit_grey";
	}
	if (dataonly && format == 'w') {
		if (putprim == ALL)
			fmtid = "48-bit_rgb";
		else
			fmtid = "16-bit_grey";
	}
					/* assign reverse ordering */
	rord[ord[0]] = 0;
	rord[ord[1]] = 1;
	rord[ord[2]] = 2;
					/* get input */
	if (i == argc) {
		fin = stdin;
	} else if (i < argc) {
		if ((fin = fopen(argv[i], "r")) == NULL) {
			fprintf(stderr, "%s: can't open file \"%s\"\n",
						progname, argv[i]);
			quit(1);
		}
		if (reverse && putprim != BRIGHT && i == argc-3) {
			if ((fin2 = fopen(argv[i+1], "r")) == NULL) {
				fprintf(stderr, "%s: can't open file \"%s\"\n",
						progname, argv[i+1]);
				quit(1);
			}
			if ((fin3 = fopen(argv[i+2], "r")) == NULL) {
				fprintf(stderr, "%s: can't open file \"%s\"\n",
						progname, argv[i+2]);
				quit(1);
			}
			interleave = -1;
		} else if (i != argc-1)
			fin = NULL;
		if (reverse && putprim != BRIGHT && !interleave) {
			fin2 = fopen(argv[i], "r");
			fin3 = fopen(argv[i], "r");
		}
		if (skipbytes && (fseek(fin, skipbytes, 0) || (fin2 != NULL &&
				(fseek(fin2, skipbytes, 0) ||
				fseek(fin3, skipbytes, 0))))) {
			fprintf(stderr, "%s: cannot skip %ld bytes on input\n",
					progname, skipbytes);
			quit(1);
		}
	}
	if (fin == NULL) {
		fprintf(stderr, "%s: bad # file arguments\n", progname);
		quit(1);
	}

	if (reverse) {
#ifdef _WIN32
		SET_FILE_BINARY(stdout);
		if (format != 'a' && format != 'i')
			SET_FILE_BINARY(fin);
#endif
					/* get header */
		if (header) {
			if (checkheader(fin, fmtid, stdout) < 0) {
				fprintf(stderr, "%s: wrong input format\n",
						progname);
				quit(1);
			}
			if (fin2 != NULL) {
				getheader(fin2, NULL, NULL);
				getheader(fin3, NULL, NULL);
			}
		} else
			newheader("RADIANCE", stdout);
					/* get resolution */
		if ((resolution && !fgetsresolu(&picres, fin)) ||
				picres.xr <= 0 || picres.yr <= 0) {
			fprintf(stderr, "%s: missing resolution\n", progname);
			quit(1);
		}
		if (resolution && fin2 != NULL) {
			RESOLU  pres2;
			if (!fgetsresolu(&pres2, fin2) ||
					pres2.rt != picres.rt ||
					pres2.xr != picres.xr ||
					pres2.yr != picres.yr ||
					!fgetsresolu(&pres2, fin3) ||
					pres2.rt != picres.rt ||
					pres2.xr != picres.xr ||
					pres2.yr != picres.yr) {
				fprintf(stderr, "%s: resolution mismatch\n",
						progname);
				quit(1);
			}
		}
						/* add to header */
		printargs(i, argv, stdout);
		if (expval < .99 || expval > 1.01)
			fputexpos(expval, stdout);
		if (outprims != NULL) {
			if (outprims != stdprims)
				fputprims(outprims, stdout);
			fputformat(COLRFMT, stdout);
		} else				/* XYZ data */
			fputformat(CIEFMT, stdout);
		putchar('\n');
		fputsresolu(&picres, stdout);	/* always put resolution */
		valtopix();
	} else {
#ifdef _WIN32
		SET_FILE_BINARY(fin);
		if (format != 'a' && format != 'i')
			SET_FILE_BINARY(stdout);
#endif
						/* get header */
		getheader(fin, checkhead, NULL);
		if (wrongformat) {
			fprintf(stderr,
				"%s: input not a Radiance RGBE picture\n",
					progname);
			quit(1);
		}
		if (!fgetsresolu(&picres, fin)) {
			fprintf(stderr, "%s: missing resolution\n", progname);
			quit(1);
		}
		if (header) {
			printargs(i, argv, stdout);
			if (expval < .99 || expval > 1.01)
				fputexpos(expval, stdout);
			fputformat(fmtid, stdout);
			putchar('\n');
		}
		if (resolution)			/* put resolution */
			fputsresolu(&picres, stdout);
		pixtoval();
	}

	quit(0);
	return 0; /* pro forma return */
}
Пример #29
0
char *
material(void)			/* get (and print) current material */
{
	char	*mname = "mat";
	COLOR	radrgb, c2;
	double	d;

	if (c_cmname != NULL)
		mname = c_cmname;
	if (!c_cmaterial->clock)
		return(mname);		/* already current */
				/* else update output */
	c_cmaterial->clock = 0;
	if (c_cmaterial->ed > .1) {	/* emitter */
		cvtcolor(radrgb, &c_cmaterial->ed_c,
				emult*c_cmaterial->ed/(PI*WHTEFFICACY));
		if (glowdist < FHUGE) {		/* do a glow */
			fprintf(matfp, "\nvoid glow %s\n0\n0\n", mname);
			fprintf(matfp, "4 %f %f %f %f\n", colval(radrgb,RED),
					colval(radrgb,GRN),
					colval(radrgb,BLU), glowdist);
		} else {
			fprintf(matfp, "\nvoid light %s\n0\n0\n", mname);
			fprintf(matfp, "3 %f %f %f\n", colval(radrgb,RED),
					colval(radrgb,GRN),
					colval(radrgb,BLU));
		}
		return(mname);
	}
	d = c_cmaterial->rd + c_cmaterial->td +
			c_cmaterial->rs + c_cmaterial->ts;
	if ((d < 0.) | (d > 1.))
		return(NULL);
					/* check for glass/dielectric */
	if (c_cmaterial->nr > 1.1 &&
			c_cmaterial->ts > .25 && c_cmaterial->rs <= .125 &&
			c_cmaterial->td <= .01 && c_cmaterial->rd <= .01 &&
			c_cmaterial->rs_a <= .01 && c_cmaterial->ts_a <= .01) {
		cvtcolor(radrgb, &c_cmaterial->ts_c,
				c_cmaterial->ts + c_cmaterial->rs);
		if (c_cmaterial->sided) {		/* dielectric */
			colval(radrgb,RED) = pow(colval(radrgb,RED),
							1./C_1SIDEDTHICK);
			colval(radrgb,GRN) = pow(colval(radrgb,GRN),
							1./C_1SIDEDTHICK);
			colval(radrgb,BLU) = pow(colval(radrgb,BLU),
							1./C_1SIDEDTHICK);
			fprintf(matfp, "\nvoid dielectric %s\n0\n0\n", mname);
			fprintf(matfp, "5 %g %g %g %f 0\n", colval(radrgb,RED),
					colval(radrgb,GRN), colval(radrgb,BLU),
					c_cmaterial->nr);
			return(mname);
		}
							/* glass */
		fprintf(matfp, "\nvoid glass %s\n0\n0\n", mname);
		fprintf(matfp, "4 %f %f %f %f\n", colval(radrgb,RED),
				colval(radrgb,GRN), colval(radrgb,BLU),
				c_cmaterial->nr);
		return(mname);
		}
					/* check for trans */
	if (c_cmaterial->td > .01 || c_cmaterial->ts > .01) {
		double	ts, a5, a6;

		if (c_cmaterial->sided) {
			ts = sqrt(c_cmaterial->ts);	/* approximate */
			a5 = .5;
		} else {
			ts = c_cmaterial->ts;
			a5 = 1.;
		}
						/* average colors */
		d = c_cmaterial->rd + c_cmaterial->td + ts;
		cvtcolor(radrgb, &c_cmaterial->rd_c, c_cmaterial->rd/d);
		cvtcolor(c2, &c_cmaterial->td_c, c_cmaterial->td/d);
		addcolor(radrgb, c2);
		cvtcolor(c2, &c_cmaterial->ts_c, ts/d);
		addcolor(radrgb, c2);
		if (c_cmaterial->rs + ts > .0001)
			a5 = (c_cmaterial->rs*c_cmaterial->rs_a +
					ts*a5*c_cmaterial->ts_a) /
					(c_cmaterial->rs + ts);
		a6 = (c_cmaterial->td + ts) /
				(c_cmaterial->rd + c_cmaterial->td + ts);
		if (a6 < .999)
			d = c_cmaterial->rd/(1. - c_cmaterial->rs)/(1. - a6);
		else
			d = c_cmaterial->td + ts;
		scalecolor(radrgb, d);
		fprintf(matfp, "\nvoid trans %s\n0\n0\n", mname);
		fprintf(matfp, "7 %f %f %f\n", colval(radrgb,RED),
				colval(radrgb,GRN), colval(radrgb,BLU));
		fprintf(matfp, "\t%f %f %f %f\n", c_cmaterial->rs, a5, a6,
				ts/(ts + c_cmaterial->td));
		return(mname);
	}
					/* check for plastic */
	if (c_cmaterial->rs < .1) {
		cvtcolor(radrgb, &c_cmaterial->rd_c,
					c_cmaterial->rd/(1.-c_cmaterial->rs));
		fprintf(matfp, "\nvoid plastic %s\n0\n0\n", mname);
		fprintf(matfp, "5 %f %f %f %f %f\n", colval(radrgb,RED),
				colval(radrgb,GRN), colval(radrgb,BLU),
				c_cmaterial->rs, c_cmaterial->rs_a);
		return(mname);
	}
					/* else it's metal */
						/* average colors */
	cvtcolor(radrgb, &c_cmaterial->rd_c, c_cmaterial->rd);
	cvtcolor(c2, &c_cmaterial->rs_c, c_cmaterial->rs);
	addcolor(radrgb, c2);
	fprintf(matfp, "\nvoid metal %s\n0\n0\n", mname);
	fprintf(matfp, "5 %f %f %f %f %f\n", colval(radrgb,RED),
			colval(radrgb,GRN), colval(radrgb,BLU),
			c_cmaterial->rs/(c_cmaterial->rd + c_cmaterial->rs),
			c_cmaterial->rs_a);
	return(mname);
}
Пример #30
0
static int
disperse(  /* check light sources for dispersion */
	OBJREC  *m,
	RAY  *r,
	FVECT  vt,
	double  tr,
	COLOR  cet,
	COLOR  abt
)
{
	RAY  sray;
	const RAY  *entray;
	FVECT  v1, v2, n1, n2;
	FVECT  dv, v2Xdv;
	double  v2Xdvv2Xdv;
	int  success = 0;
	SRCINDEX  si;
	FVECT  vtmp1, vtmp2;
	double  dtmp1, dtmp2;
	int  l1, l2;
	COLOR  ctmp;
	int  i;
	
	/*
	 *     This routine computes dispersion to the first order using
	 *  the following assumptions:
	 *
	 *	1) The dependency of the index of refraction on wavelength
	 *		is approximated by Hartmann's equation with lambda0
	 *		equal to zero.
	 *	2) The entry and exit locations are constant with respect
	 *		to dispersion.
	 *
	 *     The second assumption permits us to model dispersion without
	 *  having to sample refracted directions.  We assume that the
	 *  geometry inside the material is constant, and concern ourselves
	 *  only with the relationship between the entering and exiting ray.
	 *  We compute the first derivatives of the entering and exiting
	 *  refraction with respect to the index of refraction.  This 
	 *  is then used in a first order Taylor series to determine the
	 *  index of refraction necessary to send the exiting ray to each
	 *  light source.
	 *     If an exiting ray hits a light source within the refraction
	 *  boundaries, we sum all the frequencies over the disc of the
	 *  light source to determine the resulting color.  A smaller light
	 *  source will therefore exhibit a sharper spectrum.
	 */

	if (!(r->crtype & REFRACTED)) {		/* ray started in material */
		VCOPY(v1, r->rdir);
		n1[0] = -r->rdir[0]; n1[1] = -r->rdir[1]; n1[2] = -r->rdir[2];
	} else {
						/* find entry point */
		for (entray = r; entray->rtype != REFRACTED;
				entray = entray->parent)
			;
		entray = entray->parent;
		if (entray->crtype & REFRACTED)		/* too difficult */
			return(0);
		VCOPY(v1, entray->rdir);
		VCOPY(n1, entray->ron);
	}
	VCOPY(v2, vt);			/* exiting ray */
	VCOPY(n2, r->ron);

					/* first order dispersion approx. */
	dtmp1 = 1./DOT(n1, v1);
	dtmp2 = 1./DOT(n2, v2);
	for (i = 0; i < 3; i++)
		dv[i] = v1[i] + v2[i] - n1[i]*dtmp1 - n2[i]*dtmp2;
		
	if (DOT(dv, dv) <= FTINY)	/* null effect */
		return(0);
					/* compute plane normal */
	fcross(v2Xdv, v2, dv);
	v2Xdvv2Xdv = DOT(v2Xdv, v2Xdv);

					/* check sources */
	initsrcindex(&si);
	while (srcray(&sray, r, &si)) {

		if (DOT(sray.rdir, v2) < MINCOS)
			continue;			/* bad source */
						/* adjust source ray */

		dtmp1 = DOT(v2Xdv, sray.rdir) / v2Xdvv2Xdv;
		sray.rdir[0] -= dtmp1 * v2Xdv[0];
		sray.rdir[1] -= dtmp1 * v2Xdv[1];
		sray.rdir[2] -= dtmp1 * v2Xdv[2];

		l1 = lambda(m, v2, dv, sray.rdir);	/* mean lambda */

		if (l1 > MAXLAMBDA || l1 < MINLAMBDA)	/* not visible */
			continue;
						/* trace source ray */
		copycolor(sray.cext, cet);
		copycolor(sray.albedo, abt);
		normalize(sray.rdir);
		rayvalue(&sray);
		if (bright(sray.rcol) <= FTINY)	/* missed it */
			continue;
		
		/*
		 *	Compute spectral sum over diameter of source.
		 *  First find directions for rays going to opposite
		 *  sides of source, then compute wavelengths for each.
		 */
		 
		fcross(vtmp1, v2Xdv, sray.rdir);
		dtmp1 = sqrt(si.dom  / v2Xdvv2Xdv / PI);

							/* compute first ray */
		VSUM(vtmp2, sray.rdir, vtmp1, dtmp1);

		l1 = lambda(m, v2, dv, vtmp2);		/* first lambda */
		if (l1 < 0)
			continue;
							/* compute second ray */
		VSUM(vtmp2, sray.rdir, vtmp1, -dtmp1);

		l2 = lambda(m, v2, dv, vtmp2);		/* second lambda */
		if (l2 < 0)
			continue;
					/* compute color from spectrum */
		if (l1 < l2)
			spec_rgb(ctmp, l1, l2);
		else
			spec_rgb(ctmp, l2, l1);
		multcolor(ctmp, sray.rcol);
		scalecolor(ctmp, tr);
		addcolor(r->rcol, ctmp);
		success++;
	}
	return(success);
}