
/*
 * (c) 1988 by George Kyriazis
 */

/*
 * Intersection routines
 */

#include	"vector.h"
#include	"ray.h"
#include	<math.h>

/* 
 * Intersect ray with sphere
 */
struct	intersect	sphere(obj, r)
struct	obj	*obj;
struct	ray	r;
{
	struct	vector	v;
	struct	vector	n;	/* normal vector */
	struct	intersect	i;
	double	b, c, d;
	double	sol1, sol2;
	struct	vector	center;

	i.obj = NULL;

/* find out what the center is at this time */
	center = svproduct( Time, obj->time );
	center = vadd( obj->data.sphere.center, center );

	v = vsub( r.pos, center );
	b = 2 * vdot( r.dir, v );
	c = vdot(v, v) - obj->data.sphere.radius;

	d = b * b - 4 * c;
	if( d < 0 )
		return i;
	d = sqrt(d);
	sol1 = ( -b + d ) / 2;
	sol2 = ( -b - d ) / 2;
	if( sol1 <= 0 )
		sol1 = sol2;
	if( sol2 <= 0 )
		sol2 = sol1;
	i.t = (sol1 < sol2) ? sol1 : sol2 ;
/* if intersection is behind eye */
	if(i.t <= 0)
		return i;
	i.obj = obj;	

/* calculate the normal.  It is just the direction of the radius */
	n = vsub(vadd(r.pos, svproduct(i.t, r.dir)), center);
	i.n = norm(n);

	return i;
}

/*
 * intersect ray with a quadrangle
 */
struct	intersect	quad(obj, r)
struct	obj	*obj;
struct	ray	r;
{
	struct	intersect	i;
	double	x0, y0, z0;
	double	dx1, dy1, dz1, dx2, dy2, dz2, qx, qy, qz;
	double	alpha, a, b, t;
	double	d, dalpha, da, db;
	struct	vector	n;
	double	pdx, pdy, pdz;
	double	size;

	i.obj = NULL;

	x0 = obj->data.quad.p1.x;
	y0 = obj->data.quad.p1.y;
	z0 = obj->data.quad.p1.z;
	dx1 = x0 - obj->data.quad.p2.x;
	dy1 = y0 - obj->data.quad.p2.y;
	dz1 = z0 - obj->data.quad.p2.z;
	dx2 = x0 - obj->data.quad.p3.x;
	dy2 = y0 - obj->data.quad.p3.y;
	dz2 = z0 - obj->data.quad.p3.z;
	qx = r.dir.x;
	qy = r.dir.y;
	qz = r.dir.z;

	d = qx * ( ( dy1 * dz2 ) - ( dy2 * dz1 ) )
		- dx1 * ( ( qy * dz2 ) - ( qz * dy2 ) )
		+ dx2 * ( ( qy * dz1 ) - ( qz * dy1 ) ) ;
/* if no intersection */
	if( ABS(d) < MINT )
		return i;

/* use the right time */
	pdx = x0 - r.pos.x + Time * obj->time.x;
	pdy = y0 - r.pos.y + Time * obj->time.y;
	pdz = z0 - r.pos.z + Time * obj->time.z;

	dalpha = pdx * ( ( dy1 * dz2 ) - ( dz1 * dy2 ) )
		- dx1 * ( ( pdy * dz2 ) - ( pdz * dy2 ) )
		+ dx2 * ( ( pdy * dz1 ) - ( pdz * dy1 ) ) ;
	alpha = dalpha / d;

/* if intersection behind the eye */
	if( alpha <= 0 )
		return i;

	da = qx * ( ( pdy * dz2 ) - ( pdz * dy2 ) )
		- pdx * ( ( qy * dz2 ) - ( qz * dy2 ) )
		+ dx2 * ( ( qy * pdz ) - ( qz * pdy ) ) ;

	db = qx * ( ( dy1 * pdz ) - ( dz1 * pdy ) )
		- dx1 * ( ( qy * pdz ) - ( qz * pdy ) )
		+ pdx * ( ( qy * dz1 ) - ( qz * dy1 ) );

	a = da / d;
	b = db / d;

/* check if intersection within quad */
	if( ( a < 0 ) || ( a > 1 ) )
		return i;
	if( ( b < 0 ) || ( b > 1 ) )
		return i;

/* assign the object */
	i.obj = obj;
	i.t = alpha;
/* normal to the plane */
	n.x = dy1 * dz2 - dy2 * dz1;
	n.y = - ( dx1 * dz2 - dx2 * dz1 );
	n.z = dx1 * dy2 - dx2 * dy1;
	i.n = norm(n);

/* reverse the normal if desired */
	if( vdot( i.n, r.dir ) > 0 )
		i.n = vneg( i.n );

	return i;
}



struct	intersect	intersect(r)
struct	ray	r;
{
	int	i;
	struct	intersect	inter, intermin;

	intermin.obj = NULL;

	for(i = 0; i < noo; i++) {
		objtestline++;
/* choose the appropriate routine for each object */
		switch( obj[i].type ) {
			case SPHERE:
				inter = sphere( &obj[i], r);
				break;
			case SQUARE:
				inter = quad( &obj[i], r);
				break;
			default:
				inter.obj = NULL;
				break;
		}
/* update the minimum intersection distance if the new intersection  */
/* exists (ray intersects the object), and the intersection distance */
/* is smaller that the one logged and also the object intersected is */
/* not the object that the ray is originating from.                  */
		if( inter.obj &&
			( !intermin.obj || 
				(inter.t < intermin.t) ) &&
			( inter.obj != r.obj ) )
			intermin = inter;
	}

	return intermin;
}

