//----------------------------------------------------------------------------
// William Baxter III's Ray Tracer
//
//     Project for Comp 238, Raster Graphics
//     University of North Carolina at Chapel Hill
//     
// $Id:$
//----------------------------------------------------------------------------

#include "wb3Triangle.hpp"

//----------------------------------------------------------------------------
// CHECKS IF 2D POINT P IS IN A 2D TRI ABC.
//----------------------------------------------------------------------------
static int ptInTri2D(float Px, float Py, 
                     float Ax, float Ay, float Bx, float By, float Cx, float Cy)
{
  float dABx=Bx-Ax, dABy=By-Ay, dBCx=Cx-Bx, dBCy=Cy-By; // "REPEATS"
  if (dABx*dBCy < dABy*dBCx) // CW
  {
    if (dABx*(Py-Ay) >= dABy*(Px-Ax)) return(0);        // ABxAP
    if (dBCx*(Py-By) >= dBCy*(Px-Bx)) return(0);        // BCxBP
    if ((Ax-Cx)*(Py-Cy) >= (Ay-Cy)*(Px-Cx)) return(0);  // CAxCP
  }
  else // CCW
  {
    if (dABx*(Py-Ay) < dABy*(Px-Ax)) return(0);         // ABxAP
    if (dBCx*(Py-By) < dBCy*(Px-Bx)) return(0);         // BCxBP
    if ((Ax-Cx)*(Py-Cy) < (Ay-Cy)*(Px-Cx)) return(0);   // CAxCP
  }
  return(1); // "INSIDE" EACH EDGE'S IN-HALF-SPACE (PT P IS INSIDE TRIANGLE)
};

//----------------------------------------------------------------------------
// CHECKS IF 3D POINT P (ON ABC'S PLANE) IS IN 3D TRI ABC.
// P=PtOnTriPlane, N=PlaneNormal (does not have to be normalized)
//----------------------------------------------------------------------------
int wb3Triangle::ptInTri3D(const Vec3f& P) const
{
  #define ABS(_x) (((_x)<0)?(-(_x)):_x)  // HANDY UNIVERSAL ABSOLUTE VALUE FUNC

  // DETERMINE LARGEST COMPONENT OF NORMAL 
  //   (magnitude, since we want the largest projection)
  Vec3f N(ABS(m_N.x), ABS(m_N.y), ABS(m_N.z));

  // PROJECT ONTO PLANE WHERE PERPENDICULAR TO LARGEST NORMAL COMPONENT AXIS
  const Vec3f& A = m_vert[0];
  const Vec3f& B = m_vert[1];
  const Vec3f& C = m_vert[2];
  if (N.x>N.y && N.x>N.z)      // X IS LARGEST SO PROJECT ONTO YZ-PLANE
    return( ptInTri2D(P.y,P.z, A.y,A.z, B.y,B.z, C.y,C.z) );
  else if (N.y>N.x && N.y>N.z) // Y IS LARGEST SO PROJECT ONTO XZ-PLANE
    return( ptInTri2D(P.x,P.z, A.x,A.z, B.x,B.z, C.x,C.z) );
  else                         // Z IS LARGEST SO PROJECT ONTO XY-PLANE
    return( ptInTri2D(P.x,P.y, A.x,A.y, B.x,B.y, C.x,C.y) );
}

//----------------------------------------------------------------------------
const wb3Artifact* wb3Triangle::Intersect(const Ray3f& r, float* dist,
                                          const wb3Artifact *ignore) const
{
  const wb3Artifact *ret = wb3Plane::Intersect(r, dist, ignore);
  if (ret)
  {
    // Get the point of intersection with plane
    Vec3f isect(r[*dist]);

    // Find out if that's inside the triangle
    if (ptInTri3D(isect))
      return this;
  }
  return 0;
}
//----------------------------------------------------------------------------

