/*
 * fogdeck.c
 * $Log:	fogdeck.c,v $
 * Revision 4.0  91/07/17  14:40:28  kolb
 * Initial version.
 */
#include "atmosphe.h"
#include "fogdeck.h"
 
Fogdeck *
FogdeckCreate(alt, offset, scale, chaoscale, octaves, color, trans)
Float alt, offset, chaoscale;
Vector *scale;
int octaves;
Color *color, *trans;
{
	Fogdeck *fogdeck;
 
	fogdeck = (Fogdeck *)Malloc(sizeof(Fogdeck));
 
	fogdeck->alt = alt;
	fogdeck->octaves = octaves;
	fogdeck->scale = *scale;
	fogdeck->chaoscale = chaoscale;
	fogdeck->offset = offset;
 
	if (color == (Color *)NULL)
		fogdeck->color.r = fogdeck->color.g = fogdeck->color.b = 0.;
	else
		fogdeck->color = *color;
	if (trans == (Color *)NULL)
		fogdeck->trans.r = fogdeck->trans.g = fogdeck->trans.b =
			FAR_AWAY;
	else {
		fogdeck->trans = *trans;
	}
	return fogdeck;
}
 
/*
 * Add fogdeck to the given color.
 */
void
FogdeckApply(fogdeck, ray, pos, dist, color)
Fogdeck *fogdeck;
Ray *ray;
Vector *pos;
Float dist;
Color *color;
{
	Float atten, hitdist, density;
	Color trans;
	Vector endp;
	extern Float ExpAtten(), PAChaos();
 
	/*
	 * Find distance from origin at which ray strikes
	 * z = fogdeck->alt plane
	 */
	if (abs(ray->dir.z) < EPSILON)
		return;
	hitdist = (fogdeck->alt - ray->pos.z) / ray->dir.z;
	if (hitdist < EPSILON || hitdist > dist)
		return;
	/*
	 * Compute ray endpoint
	 */
	VecAddScaled(ray->pos, hitdist, ray->dir, &endp);
 
	/*
	 * Modify transmissivity based on point of
	 * intersection.
	 */
	endp.x *= fogdeck->scale.x;
	endp.y *= fogdeck->scale.y;
	endp.z *= fogdeck->scale.z;
 
	density = fogdeck->offset +
			fogdeck->chaoscale * PAChaos(&endp, fogdeck->octaves);
	if (density < EPSILON)
		density = HUGE;
	else
		density = 1. / density;
 
	trans = fogdeck->trans;
	ColorScale(density, trans, &trans);
 
	dist -= hitdist;
	
	atten = ExpAtten(dist, trans.r);
 
	if (trans.r == trans.g &&
	    trans.r == trans.b) {
		ColorBlend(color, &fogdeck->color, atten, 1. - atten);
		return;
	}
	color->r = atten*color->r + (1. - atten) * fogdeck->color.r;
 
	atten = ExpAtten(dist, trans.g);
	color->g = atten*color->g + (1. - atten) * fogdeck->color.g;
	atten = ExpAtten(dist, trans.b);
	color->b = atten*color->b + (1. - atten) * fogdeck->color.b;
}
