Пример #1
0
/* mix two colors according to weights given -- cres may be c1 or c2 */
void
c_cmix(C_COLOR *cres, double w1, C_COLOR *c1, double w2, C_COLOR *c2)
{
	double	scale;
	int	i;

	if (w1 == 0) {
		*cres = *c2;
		return;
	}
	if (w2 == 0) {
		*cres = *c1;
		return;
	}
	if ((c1->flags|c2->flags) & C_CDSPEC) {		/* spectral mixing */
		float	cmix[C_CNSS];

		c_ccvt(c1, C_CSSPEC|C_CSEFF);
		c_ccvt(c2, C_CSSPEC|C_CSEFF);
		if (c1->ssum*c2->ssum == 0) {
			*cres = c_dfcolor;
			return;
		}
		w1 /= c1->eff*c1->ssum;
		w2 /= c2->eff*c2->ssum;
		scale = 0.;
		for (i = 0; i < C_CNSS; i++) {
			cmix[i] = w1*c1->ssamp[i] + w2*c2->ssamp[i];
			if (cmix[i] > scale)
				scale = cmix[i];
			else if (cmix[i] < -scale)
				scale = -cmix[i];
		}
		scale = C_CMAXV / scale;
		cres->ssum = 0;
		for (i = 0; i < C_CNSS; i++)
			cres->ssum += cres->ssamp[i] = scale*cmix[i] + frand();
		cres->flags = C_CDSPEC|C_CSSPEC;
	} else {					/* CIE xy mixing */
		c_ccvt(c1, C_CSXY);
		c_ccvt(c2, C_CSXY);
		w1 *= c2->cy;
		w2 *= c1->cy;
		scale = w1 + w2;
		if (scale == 0.) {
			*cres = c_dfcolor;
			return;
		}
		scale = 1. / scale;
		cres->cx = (w1*c1->cx + w2*c2->cx) * scale;
		cres->cy = (w1*c1->cy + w2*c2->cy) * scale;
		cres->flags = C_CDXY|C_CSXY;
	}
}
Пример #2
0
/* multiply two colors -- cres may be c1 or c2 */
double
c_cmult(C_COLOR *cres, C_COLOR *c1, double y1, C_COLOR *c2, double y2)
{
	double	yres;
	int	i;

	if ((c1->flags|c2->flags) & C_CDSPEC) {
		long	cmix[C_CNSS], cmax = 0;		/* spectral multiply */

		c_ccvt(c1, C_CSSPEC|C_CSEFF);
		c_ccvt(c2, C_CSSPEC|C_CSEFF);
		for (i = 0; i < C_CNSS; i++) {
			cmix[i] = c1->ssamp[i] * c2->ssamp[i];
			if (cmix[i] > cmax)
				cmax = cmix[i];
			else if (cmix[i] < -cmax)
				cmax = -cmix[i];
		}
		cmax /= C_CMAXV;
		if (!cmax) {
			*cres = c_dfcolor;
			return(0.);
		}
		cres->ssum = 0;
		for (i = 0; i < C_CNSS; i++)
			cres->ssum += cres->ssamp[i] = cmix[i] / cmax;
		cres->flags = C_CDSPEC|C_CSSPEC;

		c_ccvt(cres, C_CSEFF);			/* below is correct */
		yres = y1 * y2 * c_y31.ssum * C_CLPWM /
			(c1->eff*c1->ssum * c2->eff*c2->ssum) *
			cres->eff*( cres->ssum*(double)cmax +
						C_CNSS/2.0*(cmax-1) );
	} else {
		float	rgb1[3], rgb2[3];		/* CIE xy multiply */

		c_toSharpRGB(c1, y1, rgb1);
		c_toSharpRGB(c2, y2, rgb2);
		
		rgb2[0] *= rgb1[0]; rgb2[1] *= rgb1[1]; rgb2[2] *= rgb1[2];

		yres = c_fromSharpRGB(rgb2, cres);
	}
	return(yres);
}
Пример #3
0
/* check if color is grey */
int
c_isgrey(C_COLOR *clr)
{
	if (!(clr->flags & (C_CSXY|C_CSSPEC)))
		return(1);		/* no settings == grey */

	c_ccvt(clr, C_CSXY);

	return(clr->cx >= .323 && clr->cx <= .343 &&
			clr->cy >= .323 && clr->cy <= .343);
}
Пример #4
0
void
cvtcolor(	/* convert a CIE XYZ color to RGB */
	COLOR	radrgb,
	register C_COLOR	*ciec,
	double	intensity
)
{
	static COLOR	ciexyz;

	c_ccvt(ciec, C_CSXY);		/* get xy representation */
	ciexyz[1] = intensity;
	ciexyz[0] = ciec->cx/ciec->cy*ciexyz[1];
	ciexyz[2] = ciexyz[1]*(1./ciec->cy - 1.) - ciexyz[0];
	cie_rgb(radrgb, ciexyz);
}
Пример #5
0
/* encode (x,y) chromaticity */
C_CHROMA
c_encodeChroma(C_COLOR *clr)
{
	double	df;
	int	ub, vb;

	c_ccvt(clr, C_CSXY);
	df = UV_NORMF/(-2.*clr->cx + 12.*clr->cy + 3.);
	ub = 4.*clr->cx*df + frand();
	if (ub > 0xff) ub = 0xff;
	else ub *= (ub > 0);
	vb = 9.*clr->cy*df + frand();
	if (vb > 0xff) vb = 0xff;
	else vb *= (vb > 0);

	return(vb<<8 | ub);
}
Пример #6
0
void
ccy2rgb(			/* convert MGF color to RGB */
	C_COLOR	*cin,	/* input MGF chrominance */
	double	cieY,	/* input luminance or reflectance */
	COLOR	cout	/* output RGB color */
)
{
	double	d;
	COLOR	xyz;
					/* get CIE XYZ representation */
	c_ccvt(cin, C_CSXY);
	d = cin->cx/cin->cy;
	xyz[CIEX] = d * cieY;
	xyz[CIEY] = cieY;
	xyz[CIEZ] = (1./cin->cy - d - 1.) * cieY;
	cie_rgb(cout, xyz);
}
Пример #7
0
/* convert to sharpened RGB color for low-error operations */
void
c_toSharpRGB(C_COLOR *cin, double cieY, float cout[3])
{
	double	xyz[3];

	c_ccvt(cin, C_CSXY);

	xyz[0] = cin->cx/cin->cy * cieY;
	xyz[1] = cieY;
	xyz[2] = (1. - cin->cx - cin->cy)/cin->cy * cieY;

	cout[0] = XYZtoSharp[0][0]*xyz[0] + XYZtoSharp[0][1]*xyz[1] +
				XYZtoSharp[0][2]*xyz[2];
	cout[1] = XYZtoSharp[1][0]*xyz[0] + XYZtoSharp[1][1]*xyz[1] +
				XYZtoSharp[1][2]*xyz[2];
	cout[2] = XYZtoSharp[2][0]*xyz[0] + XYZtoSharp[2][1]*xyz[1] +
				XYZtoSharp[2][2]*xyz[2];
}
Пример #8
0
/* Sample an individual BSDF component */
SDError
SDsampComponent(SDValue *sv, FVECT ioVec, double randX, SDComponent *sdc)
{
	float		coef[SDmaxCh];
	SDError		ec;
	FVECT		inVec;
	const SDCDst	*cd;
	double		d;
	int		n;
					/* check arguments */
	if ((sv == NULL) | (ioVec == NULL) | (sdc == NULL))
		return SDEargument;
					/* get cumulative distribution */
	VCOPY(inVec, ioVec);
	cd = (*sdc->func->getCDist)(inVec, sdc);
	if (cd == NULL)
		return SDEmemory;
	if (cd->cTotal <= 1e-6) {	/* anything to sample? */
		sv->spec = c_dfcolor;
		sv->cieY = .0;
		memset(ioVec, 0, 3*sizeof(double));
		return SDEnone;
	}
	sv->cieY = cd->cTotal;
					/* compute sample direction */
	ec = (*sdc->func->sampCDist)(ioVec, randX, cd);
	if (ec)
		return ec;
					/* get BSDF color */
	n = (*sdc->func->getBSDFs)(coef, ioVec, inVec, sdc);
	if (n <= 0) {
		strcpy(SDerrorDetail, "BSDF sample value error");
		return SDEinternal;
	}
	sv->spec = sdc->cspec[0];
	d = coef[0];
	while (--n) {
		c_cmix(&sv->spec, d, &sv->spec, coef[n], &sdc->cspec[n]);
		d += coef[n];
	}
					/* make sure everything is set */
	c_ccvt(&sv->spec, C_CSXY+C_CSSPEC);
	return SDEnone;
}
Пример #9
0
/* Return BSDF for the given incident and scattered ray vectors */
SDError
SDevalBSDF(SDValue *sv, const FVECT outVec, const FVECT inVec, const SDData *sd)
{
	int		inFront, outFront;
	SDSpectralDF	*sdf;
	float		coef[SDmaxCh];
	int		nch, i;
					/* check arguments */
	if ((sv == NULL) | (outVec == NULL) | (inVec == NULL) | (sd == NULL))
		return SDEargument;
					/* whose side are we on? */
	inFront = (inVec[2] > 0);
	outFront = (outVec[2] > 0);
					/* start with diffuse portion */
	if (inFront & outFront) {
		*sv = sd->rLambFront;
		sdf = sd->rf;
	} else if (!(inFront | outFront)) {
		*sv = sd->rLambBack;
		sdf = sd->rb;
	} else if (inFront) {
		*sv = sd->tLamb;
		sdf = (sd->tf != NULL) ? sd->tf : sd->tb;
	} else /* inBack */ {
		*sv = sd->tLamb;
		sdf = (sd->tb != NULL) ? sd->tb : sd->tf;
	}
	sv->cieY *= 1./M_PI;
					/* add non-diffuse components */
	i = (sdf != NULL) ? sdf->ncomp : 0;
	while (i-- > 0) {
		nch = (*sdf->comp[i].func->getBSDFs)(coef, outVec, inVec,
							&sdf->comp[i]);
		while (nch-- > 0) {
			c_cmix(&sv->spec, sv->cieY, &sv->spec,
					coef[nch], &sdf->comp[i].cspec[nch]);
			sv->cieY += coef[nch];
		}
	}
					/* make sure everything is set */
	c_ccvt(&sv->spec, C_CSXY+C_CSSPEC);
	return SDEnone;
}
Пример #10
0
/* Sample BSDF direction based on the given random variable */
SDError
SDsampBSDF(SDValue *sv, FVECT ioVec, double randX, int sflags, const SDData *sd)
{
	SDError		ec;
	FVECT		inVec;
	int		inFront;
	SDSpectralDF	*rdf, *tdf;
	double		rdiff;
	float		coef[SDmaxCh];
	int		i, j, n, nr;
	SDComponent	*sdc;
	const SDCDst	**cdarr = NULL;
					/* check arguments */
	if ((sv == NULL) | (ioVec == NULL) | (sd == NULL) |
			(randX < 0) | (randX >= 1.))
		return SDEargument;
					/* whose side are we on? */
	VCOPY(inVec, ioVec);
	inFront = (inVec[2] > 0);
					/* remember diffuse portions */
	if (inFront) {
		*sv = sd->rLambFront;
		rdf = sd->rf;
		tdf = (sd->tf != NULL) ? sd->tf : sd->tb;
	} else /* !inFront */ {
		*sv = sd->rLambBack;
		rdf = sd->rb;
		tdf = (sd->tb != NULL) ? sd->tb : sd->tf;
	}
	if ((sflags & SDsampDf+SDsampR) != SDsampDf+SDsampR)
		sv->cieY = .0;
	rdiff = sv->cieY;
	if ((sflags & SDsampDf+SDsampT) == SDsampDf+SDsampT)
		sv->cieY += sd->tLamb.cieY;
					/* gather non-diffuse components */
	i = nr = (((sflags & SDsampSp+SDsampR) == SDsampSp+SDsampR) &
			(rdf != NULL)) ? rdf->ncomp : 0;
	j = (((sflags & SDsampSp+SDsampT) == SDsampSp+SDsampT) &
			(tdf != NULL)) ? tdf->ncomp : 0;
	n = i + j;
	if (n > 0 && (cdarr = (const SDCDst **)malloc(n*sizeof(SDCDst *))) == NULL)
		return SDEmemory;
	while (j-- > 0) {		/* non-diffuse transmission */
		cdarr[i+j] = (*tdf->comp[j].func->getCDist)(inVec, &tdf->comp[j]);
		if (cdarr[i+j] == NULL) {
			free(cdarr);
			return SDEmemory;
		}
		sv->cieY += cdarr[i+j]->cTotal;
	}
	while (i-- > 0) {		/* non-diffuse reflection */
		cdarr[i] = (*rdf->comp[i].func->getCDist)(inVec, &rdf->comp[i]);
		if (cdarr[i] == NULL) {
			free(cdarr);
			return SDEmemory;
		}
		sv->cieY += cdarr[i]->cTotal;
	}
	if (sv->cieY <= 1e-6) {		/* anything to sample? */
		sv->cieY = .0;
		memset(ioVec, 0, 3*sizeof(double));
		return SDEnone;
	}
					/* scale random variable */
	randX *= sv->cieY;
					/* diffuse reflection? */
	if (randX < rdiff) {
		SDdiffuseSamp(ioVec, inFront, randX/rdiff);
		goto done;
	}
	randX -= rdiff;
					/* diffuse transmission? */
	if ((sflags & SDsampDf+SDsampT) == SDsampDf+SDsampT) {
		if (randX < sd->tLamb.cieY) {
			sv->spec = sd->tLamb.spec;
			SDdiffuseSamp(ioVec, !inFront, randX/sd->tLamb.cieY);
			goto done;
		}
		randX -= sd->tLamb.cieY;
	}
					/* else one of cumulative dist. */
	for (i = 0; i < n && randX < cdarr[i]->cTotal; i++)
		randX -= cdarr[i]->cTotal;
	if (i >= n)
		return SDEinternal;
					/* compute sample direction */
	sdc = (i < nr) ? &rdf->comp[i] : &tdf->comp[i-nr];
	ec = (*sdc->func->sampCDist)(ioVec, randX/cdarr[i]->cTotal, cdarr[i]);
	if (ec)
		return ec;
					/* compute color */
	j = (*sdc->func->getBSDFs)(coef, ioVec, inVec, sdc);
	if (j <= 0) {
		sprintf(SDerrorDetail, "BSDF \"%s\" sampling value error",
				sd->name);
		return SDEinternal;
	}
	sv->spec = sdc->cspec[0];
	rdiff = coef[0];
	while (--j) {
		c_cmix(&sv->spec, rdiff, &sv->spec, coef[j], &sdc->cspec[j]);
		rdiff += coef[j];
	}
done:
	if (cdarr != NULL)
		free(cdarr);
					/* make sure everything is set */
	c_ccvt(&sv->spec, C_CSXY+C_CSSPEC);
	return SDEnone;
}