Ejemplo n.º 1
0
/* Interpolate and output a BSDF function using Klems basis */
static void
eval_function(char *funame)
{
	ANGLE_BASIS	*abp = get_basis(kbasis);
	int		assignD = (fundefined(funame) < 6);
	FILE		*ofp = open_component_file(CIE_Y);
	double		iovec[6];
	double		sum;
	int		i, j, n;

	initurand(npsamps);
	for (j = 0; j < abp->nangles; j++) {	/* run through directions */
	    for (i = 0; i < abp->nangles; i++) {
		sum = 0;
		for (n = npsamps; n--; ) {	/* average over patches */
		    if (output_orient > 0)
			fo_getvec(iovec+3, j+(n+frandom())/npsamps, abp);
		    else
			bo_getvec(iovec+3, j+(n+frandom())/npsamps, abp);

		    if (input_orient > 0)
			fi_getvec(iovec, i+urand(n), abp);
		    else
			bi_getvec(iovec, i+urand(n), abp);

		    if (assignD) {
			varset("Dx", '=', -iovec[3]);
			varset("Dy", '=', -iovec[4]);
			varset("Dz", '=', -iovec[5]);
			++eclock;
		    }
		    sum += funvalue(funame, 6, iovec);
		}
		fprintf(ofp, "\t%.3e\n", sum/npsamps);
	    }
	    fputc('\n', ofp);
	    prog_show((j+1.)/abp->nangles);
	}
	prog_done();
	if (fclose(ofp)) {
		fprintf(stderr, "%s: error writing Y output\n", progname);
		exit(1);
	}
}
Ejemplo n.º 2
0
/* Interpolate and output a BSDF function using Klems basis */
static void
eval_function(char *funame)
{
	ANGLE_BASIS	*abp = get_basis(kbasis);
	int		assignD = (fundefined(funame) < 6);
	double		iovec[6];
	double		sum;
	int		i, j, n;

	initurand(npsamps);
	data_prologue();			/* begin output */
	for (j = 0; j < abp->nangles; j++) {	/* run through directions */
	    for (i = 0; i < abp->nangles; i++) {
		sum = 0;
		for (n = npsamps; n--; ) {	/* average over patches */
		    if (output_orient > 0)
			fo_getvec(iovec+3, j+(n+frandom())/npsamps, abp);
		    else
			bo_getvec(iovec+3, j+(n+frandom())/npsamps, abp);

		    if (input_orient > 0)
			fi_getvec(iovec, i+urand(n), abp);
		    else
			bi_getvec(iovec, i+urand(n), abp);

		    if (assignD) {
			varset("Dx", '=', -iovec[3]);
			varset("Dy", '=', -iovec[4]);
			varset("Dz", '=', -iovec[5]);
			++eclock;
		    }
		    sum += funvalue(funame, 6, iovec);
		}
		printf("\t%.3e\n", sum/npsamps);
	    }
	    putchar('\n');
	}
	data_epilogue();			/* finish output */
}
Ejemplo n.º 3
0
int
main(int argc, char *argv[])
{
#define	 check(ol,al)		if (argv[i][ol] || \
				badarg(argc-i-1,argv+i+1,al)) \
				goto badopt
#define	 bool(olen,var)		switch (argv[i][olen]) { \
				case '\0': var = !var; break; \
				case 'y': case 'Y': case 't': case 'T': \
				case '+': case '1': var = 1; break; \
				case 'n': case 'N': case 'f': case 'F': \
				case '-': case '0': var = 0; break; \
				default: goto badopt; }
	char	*curout = NULL;
	char	*binval = NULL;
	int	bincnt = 0;
	int	rval;
	int	i;
					/* global program name */
	progname = argv[0] = fixargv0(argv[0]);
	gargv = argv;
	gargc = argc;
					/* initialize calcomp routines early */
	initfunc();
	setcontext(RCCONTEXT);
					/* option city */
	for (i = 1; i < argc; i++) {
						/* expand arguments */
		while ((rval = expandarg(&argc, &argv, i)) > 0)
			;
		if (rval < 0) {
			sprintf(errmsg, "cannot expand '%s'", argv[i]);
			error(SYSTEM, errmsg);
		}
		if (argv[i] == NULL || argv[i][0] != '-')
			break;			/* break from options */
		if (!strcmp(argv[i], "-version")) {
			puts(VersionID);
			quit(0);
		}
		if (!strcmp(argv[i], "-defaults") ||
				!strcmp(argv[i], "-help")) {
			override_options();
			printdefaults();
			quit(0);
		}
		rval = getrenderopt(argc-i, argv+i);
		if (rval >= 0) {
			i += rval;
			continue;
		}
		switch (argv[i][1]) {
		case 'n':			/* number of cores */
			check(2,"i");
			nproc = atoi(argv[++i]);
			if (nproc <= 0)
				error(USER, "bad number of processes");
			break;
		case 'V':			/* output contributions */
			bool(2,contrib);
			break;
		case 'x':			/* x resolution */
			check(2,"i");
			xres = atoi(argv[++i]);
			break;
		case 'y':			/* y resolution */
			check(2,"i");
			yres = atoi(argv[++i]);
			break;
		case 'w':			/* warnings */
			rval = (erract[WARNING].pf != NULL);
			bool(2,rval);
			if (rval) erract[WARNING].pf = wputs;
			else erract[WARNING].pf = NULL;
			break;
		case 'e':			/* expression */
			check(2,"s");
			scompile(argv[++i], NULL, 0);
			break;
		case 'l':			/* limit distance */
			if (argv[i][2] != 'd')
				goto badopt;
			bool(3,lim_dist);
			break;
		case 'I':			/* immed. irradiance */
			bool(2,imm_irrad);
			break;
		case 'f':			/* file or force or format */
			if (!argv[i][2]) {
				check(2,"s");
				loadfunc(argv[++i]);
				break;
			}
			if (argv[i][2] == 'o') {
				bool(3,force_open);
				break;
			}
			setformat(argv[i]+2);
			break;
		case 'o':			/* output */
			check(2,"s");
			curout = argv[++i];
			break;
		case 'c':			/* input rays per output */
			check(2,"i");
			accumulate = atoi(argv[++i]);
			break;
		case 'r':			/* recover output */
			bool(2,recover);
			break;
		case 'h':			/* header output */
			bool(2,header);
			break;
		case 'b':			/* bin expression/count */
			if (argv[i][2] == 'n') {
				check(3,"s");
				bincnt = (int)(eval(argv[++i]) + .5);
				break;
			}
			check(2,"s");
			binval = argv[++i];
			break;
		case 'm':			/* modifier name */
			check(2,"s");
			addmodifier(argv[++i], curout, binval, bincnt);
			break;
		case 'M':			/* modifier file */
			check(2,"s");
			addmodfile(argv[++i], curout, binval, bincnt);
			break;
		default:
			goto badopt;
		}
	}
	if (nmods <= 0)
		error(USER, "missing required modifier argument");
					/* override some option settings */
	override_options();
					/* initialize object types */
	initotypes();
					/* initialize urand */
	if (rand_samp) {
		srandom((long)time(0));
		initurand(0);
	} else {
		srandom(0L);
		initurand(2048);
	}
					/* set up signal handling */
	sigdie(SIGINT, "Interrupt");
#ifdef SIGHUP
	sigdie(SIGHUP, "Hangup");
#endif
	sigdie(SIGTERM, "Terminate");
#ifdef SIGPIPE
	sigdie(SIGPIPE, "Broken pipe");
#endif
#ifdef SIGALRM
	sigdie(SIGALRM, "Alarm clock");
#endif
#ifdef	SIGXCPU
	sigdie(SIGXCPU, "CPU limit exceeded");
	sigdie(SIGXFSZ, "File size exceeded");
#endif
#ifdef	NICE
	nice(NICE);			/* lower priority */
#endif
					/* get octree */
	if (i == argc)
		octname = NULL;
	else if (i == argc-1)
		octname = argv[i];
	else
		goto badopt;
	if (octname == NULL)
		error(USER, "missing octree argument");

	readoct(octname, ~(IO_FILES|IO_INFO), &thescene, NULL);
	nsceneobjs = nobjects;

	marksources();			/* find and mark sources */

	setambient();			/* initialize ambient calculation */

	rcontrib();			/* trace ray contributions (loop) */

	ambsync();			/* flush ambient file */

	quit(0);	/* exit clean */

badopt:
	fprintf(stderr,
"Usage: %s [-n nprocs][-V][-r][-e expr][-f source][-o ospec][-b binv][-bn N] {-m mod | -M file} [rtrace options] octree\n",
			progname);
	sprintf(errmsg, "command line error at '%s'", argv[i]);
	error(USER, errmsg);
	return(1);	/* pro forma return */

#undef	check
#undef	bool
}
Ejemplo n.º 4
0
int
main(int  argc, char  *argv[])
{
#define	 check(ol,al)		if (argv[i][ol] || \
				badarg(argc-i-1,argv+i+1,al)) \
				goto badopt
#define	 bool(olen,var)		switch (argv[i][olen]) { \
				case '\0': var = !var; break; \
				case 'y': case 'Y': case 't': case 'T': \
				case '+': case '1': var = 1; break; \
				case 'n': case 'N': case 'f': case 'F': \
				case '-': case '0': var = 0; break; \
				default: goto badopt; }
	char  *err;
	char  *recover = NULL;
	char  *outfile = NULL;
	char  *zfile = NULL;
	int  loadflags = ~IO_FILES;
	int  seqstart = 0;
	int  persist = 0;
	int  duped1 = -1;
	int  rval;
	int  i;
					/* record start time */
	tstart = time((time_t *)NULL);
					/* global program name */
	progname = argv[0] = fixargv0(argv[0]);
					/* option city */
	for (i = 1; i < argc; i++) {
						/* expand arguments */
		while ((rval = expandarg(&argc, &argv, i)) > 0)
			;
		if (rval < 0) {
			sprintf(errmsg, "cannot expand '%s'", argv[i]);
			error(SYSTEM, errmsg);
		}
		if (argv[i] == NULL || argv[i][0] != '-')
			break;			/* break from options */
		if (!strcmp(argv[i], "-version")) {
			puts(VersionID);
			quit(0);
		}
		if (!strcmp(argv[i], "-defaults") ||
				!strcmp(argv[i], "-help")) {
			printdefaults();
			quit(0);
		}
		rval = getrenderopt(argc-i, argv+i);
		if (rval >= 0) {
			i += rval;
			continue;
		}
		rval = getviewopt(&ourview, argc-i, argv+i);
		if (rval >= 0) {
			i += rval;
			continue;
		}
						/* rpict options */
		switch (argv[i][1]) {
		case 'v':				/* view file */
			if (argv[i][2] != 'f')
				goto badopt;
			check(3,"s");
			rval = viewfile(argv[++i], &ourview, NULL);
			if (rval < 0) {
				sprintf(errmsg,
				"cannot open view file \"%s\"",
						argv[i]);
				error(SYSTEM, errmsg);
			} else if (rval == 0) {
				sprintf(errmsg,
					"bad view file \"%s\"",
						argv[i]);
				error(USER, errmsg);
			}
			break;
		case 'p':				/* pixel */
			switch (argv[i][2]) {
			case 's':				/* sample */
				check(3,"i");
				psample = atoi(argv[++i]);
				break;
			case 't':				/* threshold */
				check(3,"f");
				maxdiff = atof(argv[++i]);
				break;
			case 'j':				/* jitter */
				check(3,"f");
				dstrpix = atof(argv[++i]);
				break;
			case 'a':				/* aspect */
				check(3,"f");
				pixaspect = atof(argv[++i]);
				break;
			case 'm':				/* motion */
				check(3,"f");
				mblur = atof(argv[++i]);
				break;
			case 'd':				/* aperture */
				check(3,"f");
				dblur = atof(argv[++i]);
				break;
			default:
				goto badopt;
			}
			break;
		case 'x':				/* x resolution */
			check(2,"i");
			hresolu = atoi(argv[++i]);
			break;
		case 'y':				/* y resolution */
			check(2,"i");
			vresolu = atoi(argv[++i]);
			break;
		case 'S':				/* slave index */
			check(2,"i");
			seqstart = atoi(argv[++i]);
			break;
		case 'o':				/* output file */
			check(2,"s");
			outfile = argv[++i];
			break;
		case 'z':				/* z file */
			check(2,"s");
			zfile = argv[++i];
			break;
		case 'r':				/* recover file */
			if (argv[i][2] == 'o') {		/* +output */
				check(3,"s");
				outfile = argv[i+1];
			} else
				check(2,"s");
			recover = argv[++i];
			break;
		case 't':				/* timer */
			check(2,"i");
			ralrm = atoi(argv[++i]);
			break;
#ifdef  PERSIST
		case 'P':				/* persist file */
			if (argv[i][2] == 'P') {
				check(3,"s");
				persist = PARALLEL;
			} else {
				check(2,"s");
				persist = PERSIST;
			}
			persistfile(argv[++i]);
			break;
#endif
		case 'w':				/* warnings */
			rval = erract[WARNING].pf != NULL;
			bool(2,rval);
			if (rval) erract[WARNING].pf = wputs;
			else erract[WARNING].pf = NULL;
			break;
		case 'e':				/* error file */
			check(2,"s");
			errfile = argv[++i];
			break;
		default:
			goto badopt;
		}
	}
	err = setview(&ourview);	/* set viewing parameters */
	if (err != NULL)
		error(USER, err);
					/* initialize object types */
	initotypes();
					/* initialize urand */
	if (rand_samp) {
		srandom((long)time(0));
		initurand(0);
	} else {
		srandom(0L);
		initurand(2048);
	}
					/* set up signal handling */
	sigdie(SIGINT, "Interrupt");
#ifdef SIGHUP
	sigdie(SIGHUP, "Hangup");
#endif
	sigdie(SIGTERM, "Terminate");
#ifdef SIGPIPE
	sigdie(SIGPIPE, "Broken pipe");
#endif
#ifdef SIGALRM
	sigdie(SIGALRM, "Alarm clock");
#endif
#ifdef	SIGXCPU
	sigdie(SIGXCPU, "CPU limit exceeded");
	sigdie(SIGXFSZ, "File size exceeded");
#endif
					/* open error file */
	if (errfile != NULL) {
		if (freopen(errfile, "a", stderr) == NULL)
			quit(2);
		fprintf(stderr, "**************\n*** PID %5d: ",
				getpid());
		printargs(argc, argv, stderr);
		putc('\n', stderr);
		fflush(stderr);
	}
#ifdef	NICE
	nice(NICE);			/* lower priority */
#endif
					/* get octree */
	if (i == argc)
		octname = NULL;
	else if (i == argc-1)
		octname = argv[i];
	else
		goto badopt;
	if (seqstart > 0 && octname == NULL)
		error(USER, "missing octree argument");
					/* set up output */
#ifdef  PERSIST
	if (persist) {
		if (recover != NULL)
			error(USER, "persist option used with recover file");
		if (seqstart <= 0)
			error(USER, "persist option only for sequences");
		if (outfile == NULL)
		duped1 = dup(fileno(stdout));	/* don't lose our output */
		openheader();
	} else
#endif
	if (outfile != NULL)
		openheader();
#ifdef	_WIN32
	SET_FILE_BINARY(stdout);
	if (octname == NULL)
		SET_FILE_BINARY(stdin);
#endif
	readoct(octname, loadflags, &thescene, NULL);
	nsceneobjs = nobjects;

	if (loadflags & IO_INFO) {	/* print header */
		printargs(i, argv, stdout);
		printf("SOFTWARE= %s\n", VersionID);
	}

	marksources();			/* find and mark sources */

	setambient();			/* initialize ambient calculation */

#ifdef  PERSIST
	if (persist) {
		fflush(stdout);
		if (outfile == NULL) {		/* reconnect stdout */
			dup2(duped1, fileno(stdout));
			close(duped1);
		}
		if (persist == PARALLEL) {	/* multiprocessing */
			preload_objs();		/* preload scene */
			shm_boundary = (char *)malloc(16);
			strcpy(shm_boundary, "SHM_BOUNDARY");
			while ((rval=fork()) == 0) {	/* keep on forkin' */
				pflock(1);
				pfhold();
				tstart = time((time_t *)NULL);
				ambsync();		/* load new values */
			}
			if (rval < 0)
				error(SYSTEM, "cannot fork child for persist function");
			pfdetach();		/* parent will run then exit */
		}
	}
runagain:
	if (persist) {
		if (outfile == NULL)			/* if out to stdout */
			dupheader();			/* send header */
		else					/* if out to file */
			duped1 = dup(fileno(stdout));	/* hang onto pipe */
	}
#endif
					/* batch render picture(s) */
	rpict(seqstart, outfile, zfile, recover);
					/* flush ambient file */
	ambsync();
#ifdef  PERSIST
	if (persist == PERSIST) {	/* first run-through */
		if ((rval=fork()) == 0) {	/* child loops until killed */
			pflock(1);
			persist = PCHILD;
		} else {			/* original process exits */
			if (rval < 0)
				error(SYSTEM, "cannot fork child for persist function");
			pfdetach();		/* parent exits */
		}
	}
	if (persist == PCHILD) {	/* wait for a signal then go again */
		if (outfile != NULL)
			close(duped1);		/* release output handle */
		pfhold();
		tstart = time((time_t *)NULL);	/* reinitialize */
		raynum = nrays = 0;
		goto runagain;
	}
#endif
	quit(0);

badopt:
	sprintf(errmsg, "command line error at '%s'", argv[i]);
	error(USER, errmsg);
	return 1; /* pro forma return */

#undef	check
#undef	bool
}
Ejemplo n.º 5
0
/* Load and resample XML BSDF description using Klems basis */
static void
eval_bsdf(const char *fname)
{
	ANGLE_BASIS	*abp = get_basis(kbasis);
	FILE		*cfp[3];
	SDData		bsd;
	SDError		ec;
	FVECT		vin, vout;
	SDValue		sdv;
	double		sum, xsum, ysum;
	int		i, j, n;

	initurand(npsamps);
	SDclearBSDF(&bsd, fname);		/* load BSDF file */
	if ((ec = SDloadFile(&bsd, fname)) != SDEnone)
		goto err;
	if (bsd.mgf != NULL)			/* save geometry */
		save_geom(bsd.mgf);
	if (bsd.matn[0])			/* save identifier(s) */
		strcpy(bsdf_name, bsd.matn);
	if (bsd.makr[0])
		strcpy(bsdf_manuf, bsd.makr);
	if (bsd.dim[2] > 0) {			/* save dimension(s) */
		char	buf[64];
		if ((bsd.dim[0] > 0) & (bsd.dim[1] > 0))
			sprintf(buf, "w=%g;h=%g;t=%g",
					bsd.dim[0], bsd.dim[1], bsd.dim[2]);
		else
			sprintf(buf, "t=%g", bsd.dim[2]);
		add_wbsdf("-f", 1);
		add_wbsdf(buf, 0);
	}
						/* front reflection */
	if (bsd.rf != NULL || bsd.rLambFront.cieY > .002) {
	    input_orient = 1; output_orient = 1;
	    cfp[CIE_Y] = open_component_file(CIE_Y);
	    if (bsd.rf != NULL && bsd.rf->comp[0].cspec[2].flags) {
		rbf_colorimetry = RBCtristimulus;
		cfp[CIE_X] = open_component_file(CIE_X);
		cfp[CIE_Z] = open_component_file(CIE_Z);
	    } else
		rbf_colorimetry = RBCphotopic;
	    for (j = 0; j < abp->nangles; j++) {
	        for (i = 0; i < abp->nangles; i++) {
		    sum = 0;			/* average over patches */
		    xsum = ysum = 0;
		    for (n = npsamps; n-- > 0; ) {
			fo_getvec(vout, j+(n+frandom())/npsamps, abp);
			fi_getvec(vin, i+urand(n), abp);
			ec = SDevalBSDF(&sdv, vout, vin, &bsd);
			if (ec != SDEnone)
				goto err;
			sum += sdv.cieY;
			if (rbf_colorimetry == RBCtristimulus) {
				xsum += sdv.cieY * sdv.spec.cx;
				ysum += sdv.cieY * sdv.spec.cy;
			}
		    }
		    fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
		    if (rbf_colorimetry == RBCtristimulus) {
			fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
			fprintf(cfp[CIE_Z], "\t%.3e\n",
				(sum - xsum - ysum)*sum/(npsamps*ysum));
		    }
		}
		fputc('\n', cfp[CIE_Y]);	/* extra space between rows */
		if (rbf_colorimetry == RBCtristimulus) {
			fputc('\n', cfp[CIE_X]);
			fputc('\n', cfp[CIE_Z]);
		}
	    }
	    if (fclose(cfp[CIE_Y])) {
		fprintf(stderr, "%s: error writing Y output\n", progname);
		exit(1);
	    }
	    if (rbf_colorimetry == RBCtristimulus &&
			(fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
		fprintf(stderr, "%s: error writing X/Z output\n", progname);
		exit(1);
	    }
	}
						/* back reflection */
	if (bsd.rb != NULL || bsd.rLambBack.cieY > .002) {
	    input_orient = -1; output_orient = -1;
	    cfp[CIE_Y] = open_component_file(CIE_Y);
	    if (bsd.rb != NULL && bsd.rb->comp[0].cspec[2].flags) {
		rbf_colorimetry = RBCtristimulus;
		cfp[CIE_X] = open_component_file(CIE_X);
		cfp[CIE_Z] = open_component_file(CIE_Z);
	    } else
		rbf_colorimetry = RBCphotopic;
	    for (j = 0; j < abp->nangles; j++) {
	        for (i = 0; i < abp->nangles; i++) {
		    sum = 0;			/* average over patches */
		    xsum = ysum = 0;
		    for (n = npsamps; n-- > 0; ) {
			bo_getvec(vout, j+(n+frandom())/npsamps, abp);
			bi_getvec(vin, i+urand(n), abp);
			ec = SDevalBSDF(&sdv, vout, vin, &bsd);
			if (ec != SDEnone)
				goto err;
			sum += sdv.cieY;
			if (rbf_colorimetry == RBCtristimulus) {
				xsum += sdv.cieY * sdv.spec.cx;
				ysum += sdv.cieY * sdv.spec.cy;
			}
		    }
		    fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
		    if (rbf_colorimetry == RBCtristimulus) {
			fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
			fprintf(cfp[CIE_Z], "\t%.3e\n",
				(sum - xsum - ysum)*sum/(npsamps*ysum));
		    }
		}
		if (rbf_colorimetry == RBCtristimulus) {
			fputc('\n', cfp[CIE_X]);
			fputc('\n', cfp[CIE_Z]);
		}
	    }
	    if (fclose(cfp[CIE_Y])) {
		fprintf(stderr, "%s: error writing Y output\n", progname);
		exit(1);
	    }
	    if (rbf_colorimetry == RBCtristimulus &&
			(fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
		fprintf(stderr, "%s: error writing X/Z output\n", progname);
		exit(1);
	    }
	}
						/* front transmission */
	if (bsd.tf != NULL || bsd.tLamb.cieY > .002) {
	    input_orient = 1; output_orient = -1;
	    cfp[CIE_Y] = open_component_file(CIE_Y);
	    if (bsd.tf != NULL && bsd.tf->comp[0].cspec[2].flags) {
		rbf_colorimetry = RBCtristimulus;
		cfp[CIE_X] = open_component_file(CIE_X);
		cfp[CIE_Z] = open_component_file(CIE_Z);
	    } else
		rbf_colorimetry = RBCphotopic;
	    for (j = 0; j < abp->nangles; j++) {
	        for (i = 0; i < abp->nangles; i++) {
		    sum = 0;			/* average over patches */
		    xsum = ysum = 0;
		    for (n = npsamps; n-- > 0; ) {
			bo_getvec(vout, j+(n+frandom())/npsamps, abp);
			fi_getvec(vin, i+urand(n), abp);
			ec = SDevalBSDF(&sdv, vout, vin, &bsd);
			if (ec != SDEnone)
				goto err;
			sum += sdv.cieY;
			if (rbf_colorimetry == RBCtristimulus) {
				xsum += sdv.cieY * sdv.spec.cx;
				ysum += sdv.cieY * sdv.spec.cy;
			}
		    }
		    fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
		    if (rbf_colorimetry == RBCtristimulus) {
			fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
			fprintf(cfp[CIE_Z], "\t%.3e\n",
				(sum - xsum - ysum)*sum/(npsamps*ysum));
		    }
		}
		if (rbf_colorimetry == RBCtristimulus) {
			fputc('\n', cfp[CIE_X]);
			fputc('\n', cfp[CIE_Z]);
		}
	    }
	    if (fclose(cfp[CIE_Y])) {
		fprintf(stderr, "%s: error writing Y output\n", progname);
		exit(1);
	    }
	    if (rbf_colorimetry == RBCtristimulus &&
			(fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
		fprintf(stderr, "%s: error writing X/Z output\n", progname);
		exit(1);
	    }
	}
						/* back transmission */
	if ((bsd.tb != NULL) | (bsd.tf != NULL)) {
	    input_orient = -1; output_orient = 1;
	    cfp[CIE_Y] = open_component_file(CIE_Y);
	    if (bsd.tb != NULL)
		rbf_colorimetry = bsd.tb->comp[0].cspec[2].flags
					? RBCtristimulus : RBCphotopic ;
	    if (rbf_colorimetry == RBCtristimulus) {
		cfp[CIE_X] = open_component_file(CIE_X);
		cfp[CIE_Z] = open_component_file(CIE_Z);
	    }
	    for (j = 0; j < abp->nangles; j++) {
	        for (i = 0; i < abp->nangles; i++) {
		    sum = 0;		/* average over patches */
		    xsum = ysum = 0;
		    for (n = npsamps; n-- > 0; ) {
			fo_getvec(vout, j+(n+frandom())/npsamps, abp);
			bi_getvec(vin, i+urand(n), abp);
			ec = SDevalBSDF(&sdv, vout, vin, &bsd);
			if (ec != SDEnone)
				goto err;
			sum += sdv.cieY;
			if (rbf_colorimetry == RBCtristimulus) {
				xsum += sdv.cieY * sdv.spec.cx;
				ysum += sdv.cieY * sdv.spec.cy;
			}
		    }
		    fprintf(cfp[CIE_Y], "\t%.3e\n", sum/npsamps);
		    if (rbf_colorimetry == RBCtristimulus) {
			fprintf(cfp[CIE_X], "\t%.3e\n", xsum*sum/(npsamps*ysum));
			fprintf(cfp[CIE_Z], "\t%.3e\n",
				(sum - xsum - ysum)*sum/(npsamps*ysum));
		    }
		}
		if (rbf_colorimetry == RBCtristimulus) {
			fputc('\n', cfp[CIE_X]);
			fputc('\n', cfp[CIE_Z]);
		}
	    }
	    if (fclose(cfp[CIE_Y])) {
		fprintf(stderr, "%s: error writing Y output\n", progname);
		exit(1);
	    }
	    if (rbf_colorimetry == RBCtristimulus &&
			(fclose(cfp[CIE_X]) || fclose(cfp[CIE_Z]))) {
		fprintf(stderr, "%s: error writing X/Z output\n", progname);
		exit(1);
	    }
	}
	SDfreeBSDF(&bsd);			/* all done */
	return;
err:
	SDreportError(ec, stderr);
	exit(1);
}