/* PhBConeTextureProjection.C: PhBConeTextureProjection nodes (public source) */

#include "PhBConeTextureProjection.H"

namespace xrml {

void PhBConeTextureProjection::render(void)
{
  Warning(NULL, "PhBConeTextureProjection::render(): not yet implemented");
}

Vec3 PhBConeTextureProjection::object2surface(const Vec3& objectCoord,
					      Vec3 *x,
					      Vec3 *y,
					      Vec3 *z)
{
  // generate (u,v) according to VRML-spec (6.11)
  // and generate axis (Z = surface-normal)
  double h = height / 2;
  double u=0., v=0.;

  // determine if point is on SIDE or on BOTTOM
  // use side when
  //   1)  no bottom exists
  //   2)  z-coord lays above bottom-surface
  if ( !(bottom) || (objectCoord.y >= (EPSILON - h)) )
    {
      // calc closest point on side, assume y coord and direction (x, z) is correct
      double t = (height > EPSILON) ? 
	         (h - objectCoord.y) / height : 
	          1;
      double r = t * bottomRadius;
      double l = sqrt((objectCoord.x * objectCoord.x) + (objectCoord.z * objectCoord.z));
      double f = r / l;

      Vec3 p(f * objectCoord.x, objectCoord.y, f * objectCoord.z);

      if (x && y && z) {
	if(objectCoord.y <= (h - EPSILON))
	  {
	    *x = Vec3(0, 0, 1);
	    *y = Vec3(1, 0, 0);
	  }
	else {
	  *x = Vec3(p.z, 0,  -p.x).normalize();
	  *y = Vec3(-p.x, h - p.y, -p.z).normalize();
	}

	*z = *x ^ *y;
      }

      u = .5 - atan2(-p.x, p.z) / (2 * M_PI);;
      v = t;
    }

  // use bottom otherwise
  else          
    {
      double l = 1. / sqrt((objectCoord.x * objectCoord.x) + (objectCoord.z * objectCoord.z));
      Vec3 p(l * objectCoord.x, 0. , l * objectCoord.z);

      if (x && y && z) {
	*z = Vec3( 0, -1, 0);	// points down (bottom side)
	*y = Vec3(-p.x, 0, -p.z);	// points to center of bottom disc
	*x = Vec3(-p.z, 0, p.x);	// along circles around center of bottom disc
      }

      double i = .5 / bottomRadius;
      u = .5 + (objectCoord.x * i); 
      v = .5 + (objectCoord.z * i); 
    }

  // clip point that fall out of the [0, 1) to 1
  return Vec3( (u < 1) ? u : 1 ,
	       (v < 1) ? v : 1 ,
	       0 );
}

}  // namespace xrml
