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

#include "PhBCylinderTextureProjection.H"

namespace xrml {

void PhBCylinderTextureProjection::render(void)
{
  // needs to do nothing
}

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

  // Determine if point is on the top, bottom or side
  //  above top-plane (& exists) -> top
  //  under bottom-plane (& exists) -> bottom
  //  else side
  if ((objectCoord.y >= h - EPSILON) && top)           // TOP
    {
      double i = .5 / radius;

      if (x && y && z) {
	*z = Vec3(0, 1, 0);
	// Y points to center of top disc
	*y = Vec3(-p.x, 0, -p.z);
	// X = Y ^ Z (makes circles around center in counterclockwise direction)
	*x = Vec3(p.z, 0, -p.x);
      }

      u = .5 + (objectCoord.x * i); 
      v = .5 - (objectCoord.z * i); 
    }
  else if ((objectCoord.y <= EPSILON - h) && bottom)  // BOTTOM
    {
      double i = .5 / radius;

      if (x && y && z) {
	*z = Vec3( 0, -1, 0);
	// Y points to center of bottom disc
	*y = Vec3(-p.x, 0, -p.z);
	// X = Y ^ Z
	*x = Vec3(-p.z, 0, p.x);
      }

      u = .5 + (objectCoord.x * i); 
      v = .5 + (objectCoord.z * i); 
    }
  else if(side) {                                  // SIDE
      // calc closest point on side, assume y coord and direction (x, z) is correct
    // TODO: why must Y point down in order to give the impression that it 
    // points towards to top of the cylinder???
      if (x && y && z) {
	*x = Vec3(p.z, 0,  -p.x);
	*y = Vec3(0, -1, 0);
	*z = Vec3(p.x, 0, p.z);
      }

      u = .5 - atan2(-p.x, p.z) / (2 * M_PI);
      v = (height > EPSILON) ? (h - objectCoord.y) / height : 1;
  }

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

}  // namespace xrml
