/* transform.H: superclass for all nodes containing 3D transforms */

#ifndef _XRML_TRANSFORM_BEHAVIOUR_H_
#define _XRML_TRANSFORM_BEHAVIOUR_H_

#include "xrml.H"
#include "matrix.H"

namespace xrml {

class transform {
public:
  SFVec3f        center;
  SFRotation     rotation;
  SFVec3f        scale;
  SFRotation     scaleOrientation;
  SFVec3f        translation;

  // 4x4 transform matrix expressing the combined transform + inverse
  Mat4		 xf, inverse_xf;

  transform()
  {
    center = SFVec3f(0,0,0);
    rotation = SFRotation(0,0,1,0);
    scale = SFVec3f(1,1,1);
    scaleOrientation = SFRotation(0,0,1,0);
    translation = SFVec3f(0,0,0);

    xf = Mat4(); 		// initialized to identity transform
    inverse_xf = Mat4(); 	
  }

  // Routines below compose the direct and inverse 4x4 transform matrix
  // corresponding to the transform node.
  // Not particularly the most efficient solution, but we'll see later how
  // bad it is.
  virtual void work_out(void)
  {
    xf = xf.translation(-Vec3(center)) *
      xf.rotation(-Vec4(scaleOrientation)) *
      xf.scaling(Vec3(scale)) *
      xf.rotation(Vec4(scaleOrientation)) *
      xf.rotation(Vec4(rotation)) *
      xf.translation(Vec3(center)) *
      xf.translation(Vec3(translation));
  }

  virtual void work_out_inverse(void) 
  {
    inverse_xf = 
      xf.translation(-Vec3(translation)) *
      xf.translation(-Vec3(center)) *
      xf.rotation(-Vec4(rotation)) *
      xf.rotation(-Vec4(scaleOrientation)) *
      xf.scaling(Vec3(fabs(scale.x) > EPSILON ? 1./scale.x : 1.,
		      fabs(scale.y) > EPSILON ? 1./scale.y : 1.,
		      fabs(scale.z) > EPSILON ? 1./scale.z : 1.));
      xf.rotation(Vec4(scaleOrientation)) *
      xf.translation(Vec3(center));
  }
};

}  // namespace xrml

#endif /*_XRML_TRANSFORM_BEHAVIOUR_H_*/
