
/* Copyright (C) 1999-2000 by Peter Eastman

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY 
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */

package artofillusion.raytracer;

import artofillusion.*;
import artofillusion.math.*;

/** A Ray is defined by two vectors: an origin and a direction.  In addition, every ray has
    a unique ID number which can be used to avoid repeated intersection tests.  Modifying the
    ray automatically causes its ID number to be updated. */

public class Ray
{
  Vec3 origin, direction;
  int id;
  static int nextid = 0;

  public Ray()
  {
    origin = new Vec3();
    direction = new Vec3();
    id = nextid++;
  }

  public final void setRay(Vec3 orig, Vec3 dir)
  {
    origin.set(orig);
    direction.set(dir);
    id = nextid++;
  }

  public final Vec3 getOrigin()
  {
    return origin;
  }

  public final Vec3 getDirection()
  {
    return direction;
  }

  public final int getID()
  {
    return id;
  }

  public void newID()
  {
    id = nextid++;
  }
  
  /** Determine whether this ray intersects a BoundingBox. */
  
  public boolean intersects(BoundingBox bb)
  {
    double t1, t2, len;
    double mint = -Double.MAX_VALUE;
    double maxt = Double.MAX_VALUE;
    if (direction.x == 0.0)
      {
	if (origin.x < bb.minx || origin.x > bb.maxx)
	  return false;
      }
    else
      {
	t1 = (bb.minx-origin.x)/direction.x;
	t2 = (bb.maxx-origin.x)/direction.x;
	if (t1 < t2)
	  {
	    if (t1 > mint)
	      mint = t1;
	    if (t2 < maxt)
	      maxt = t2;
	  }
	else
	  {
	    if (t2 > mint)
	      mint = t2;
	    if (t1 < maxt)
	      maxt = t1;
	  }
	if (mint > maxt || maxt < 0.0)
	  return false;
      }
    if (direction.y == 0.0)
      {
	if (origin.y < bb.miny || origin.y > bb.maxy)
	  return false;
      }
    else
      {
	t1 = (bb.miny-origin.y)/direction.y;
	t2 = (bb.maxy-origin.y)/direction.y;
	if (t1 < t2)
	  {
	    if (t1 > mint)
	      mint = t1;
	    if (t2 < maxt)
	      maxt = t2;
	  }
	else
	  {
	    if (t2 > mint)
	      mint = t2;
	    if (t1 < maxt)
	      maxt = t1;
	  }
	if (mint > maxt || maxt < 0.0)
	  return false;
      }
    if (direction.z == 0.0)
      {
	if (origin.z < bb.minz || origin.z > bb.maxz)
	  return false;
      }
    else
      {
	t1 = (bb.minz-origin.z)/direction.z;
	t2 = (bb.maxz-origin.z)/direction.z;
	if (t1 < t2)
	  {
	    if (t1 > mint)
	      mint = t1;
	    if (t2 < maxt)
	      maxt = t2;
	  }
	else
	  {
	    if (t2 > mint)
	      mint = t2;
	    if (t1 < maxt)
	      maxt = t1;
	  }
	if (mint > maxt || maxt < 0.0)
	  return false;
      }
    return true;
  }
}