#ifndef __OGL2_VECTOR3_H__
#define __OGL2_VECTOR3_H__

#if !defined (__GNUG__) && !defined (__attribute__)
#define __attribute__(foo) /* Ignore.  */
#endif

#include <iostream>

extern "C++" {

template <class __type>
struct Vector3 {
  __type x;
  __type y;
  __type z;

  Vector3() :
    x(0), y(0), z(0) {}
  Vector3(__type _x, __type _y, __type _z) :
    x(_x), y(_y), z(_z) {}

  Vector3<__type>& operator () (__type _x, __type _y, __type _z) {
    x = _x; y = _y; z = _z;
    return *this;
  }
  Vector3<__type>& operator () (const Vector3<__type>& b) {
    x = b.x;
    y = b.y;
    z = b.z;
    return *this;
  }
  Vector3<__type>& operator += (const Vector3<__type>& b) {
    x += b.x;
    y += b.y;
    z += b.z;
    return *this;
  }
  Vector3<__type>& operator -= (const Vector3<__type>& b) {
    x -= b.x;
    y -= b.y;
    z -= b.z;
    return *this;
  }
  Vector3<__type>& operator *= (const Vector3<__type>& b) {
    x *= b.x;
    y *= b.y;
    z *= b.z;
    return *this;
  }
  Vector3<__type>& operator *= (__type s) {
    x *= s;
    y *= s;
    z *= s;
    return *this;
  }

  __type Length () {
    return sqrt(x*x + y*y + z*z);
  }
  __type Len () {
    return Length();
  }

  void Unpack(__type* u) {
    u[0] = x;
    u[1] = y;
    u[2] = z;
  }
};

template struct Vector3<GLfloat>;
template struct Vector3<GLdouble>;

typedef Vector3<GLfloat> Vector3f;
typedef Vector3<GLdouble> Vector3d;

template <class __type>
ostream& operator << (ostream& s, const Vector3<__type>& a) {
  return s << "(" << a.x << "," << a.y << "," << a.z << ")";
}

template <class __type> inline Vector3<__type>
operator + (const Vector3<__type>& a) __attribute__ ((const));

template <class __type> inline Vector3<__type>
operator + (const Vector3<__type>& a) {
  return a;
}

template <class __type> inline Vector3<__type>
operator - (const Vector3<__type>& a) __attribute__ ((const));

template <class __type> inline Vector3<__type>
operator - (const Vector3<__type>& a) {
  return Vector3<__type> (-a.x, -a.y, -a.z);
}

template <class __type> inline Vector3<__type>
operator + (const Vector3<__type>& a, const Vector3<__type>& b) __attribute__ ((const));

template <class __type> inline Vector3<__type>
operator + (const Vector3<__type>& a, const Vector3<__type>& b) {
  return Vector3<__type> (a.x+b.x, a.y+b.y, a.z+b.z);
}

template <class __type> inline Vector3<__type>
operator - (const Vector3<__type>& a, const Vector3<__type>& b) __attribute__ ((const));

template <class __type> inline Vector3<__type>
operator - (const Vector3<__type>& a, const Vector3<__type>& b) {
  return Vector3<__type> (a.x-b.x, a.y-b.y, a.z-b.z);
}

template <class __type> inline Vector3<__type>
operator * (const Vector3<__type>& a, __type s) __attribute__ ((const));

template <class __type> inline Vector3<__type>
operator * (const Vector3<__type>& a, __type s)
{
  return Vector3<__type> (a.x*s, a.y*s, a.z*s);
}

template <class __type> inline Vector3<__type>
operator * (__type s, const Vector3<__type>& a) __attribute__ ((const));

template <class __type> inline Vector3<__type>
operator * (__type s, const Vector3<__type>& a)
{
  return Vector3<__type> (s*a.x, s*a.y, s*a.z);
}

template <class __type> inline Vector3<__type>
operator * (const Vector3<__type>& a, const Vector3<__type>& b) __attribute__ ((const));

template <class __type> inline Vector3<__type>
operator * (const Vector3<__type>& a, const Vector3<__type>& b) {
  return Vector3<__type> (a.x*b.x, a.y*b.y, a.z*b.z);
}

template <class __type> inline __type
Dot (const Vector3<__type>& a, const Vector3<__type>& b) __attribute__ ((const));

template <class __type> inline __type
Dot (const Vector3<__type>& a, const Vector3<__type>& b) {
  return (a.x*b.x + a.y*b.y + a.z*b.z);
}

template <class __type> inline Vector3<__type>
Cross (const Vector3<__type>& u, const Vector3<__type>& v) __attribute__ ((const));

template <class __type> inline Vector3<__type>
Cross (const Vector3<__type>& u, const Vector3<__type>& v) {
  return Vector3<__type> ( u.y*v.z-u.z*v.y, u.z*v.x-u.x*v.z, u.x*v.y-u.y*v.x);
}


} // extern "C++"

#endif 
