/*-
 * Copyright (c) 1999,2000 Qube Software, Ltd.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of the source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Any redistribution solely in binary form must conspicuously
 *    reproduce the following disclaimer in documentation provided with the
 *    binary redistribution.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'', WITHOUT ANY WARRANTIES, EXPRESS
 * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  LICENSOR SHALL
 * NOT BE LIABLE FOR ANY LOSS OR DAMAGES RESULTING FROM THE USE OF THIS
 * SOFTWARE, EITHER ALONE OR IN COMBINATION WITH ANY OTHER SOFTWARE.
 * 
 * 	$Id: vec3.h,v 1.28 2000/05/30 17:03:11 hugh Exp $
 */

#ifndef __vec3_h__
#define __vec3_h__

MATHS_BEGIN

struct Matrix3f;
struct Matrix4f;
struct Affine4f;


template<class T> struct Vec2;
template<class T> struct Vec3;
template<class T> struct Vec4;

template<class T>
struct EXPORT_QMATHS Vec3
{
    T x;
    T y;
    T z;

    // Constructors
			Vec3() {}
                        Vec3(T v) 
                            : x(v), y(v), z(v) {}
			Vec3(T tx, T ty, T tz)
			    : x(tx), y(ty), z(tz) {}
			Vec3(const Vec2<T>& v)
			    : x(v.x), y(v.y), z(0) {}
			Vec3(const Vec4<T>& v)
			    : x(v.x / v.w), y(v.y / v.w), z(v.z / v.w) {}

    // Accessors
    T&			operator[](unsigned int i);
    const T&		operator[](unsigned int i) const;
    Vec2<T>&            vec2() 
                            { return(*(Vec2<T> *)&x); }
    const Vec2<T>&      vec2() const
                            { return(*(Vec2<T> *)&x); }
    bool                isZero() const;

    // Assignment operators
    Vec3&		operator+=(const Vec3&);
    Vec3&		operator-=(const Vec3&);
    Vec3&		operator*=(const Vec3&);
    Vec3&		operator/=(const Vec3&);
    Vec3&		operator*=(T);
    Vec3&		operator/=(T);

    // Testing
    int			operator==(const T&) const;
    int			operator!=(const T& i) const
                            {
                                return !(*this == i);
                            }
    T			modulus() const;
    T                   length() const { return(modulus()); } 
    T                   lengthSquared() const;
    T                   distanceTo(const Vec3 &there) const;
    T                   distanceToSquared(const Vec3 &there) const;

    
    bool                equal(const Vec3& v, T e = Epsilon) const;

    // Modifying
    void                normalize();
    Vec3&               scaleTo(T newlen);
    void                zero();
    void                clamp(const T min, const T max); 
    Vec3&               sub(const Vec3 &a, const Vec3 &b);  // this = a - b
    Vec3&               negate();

    // Geometric operations
    Vec3&               cross(const Vec3&, const Vec3&);  // puts result in *this
    T                   dot(const Vec3& b) const;         // puts result in *this
    void                setNormalTo(const Vec3 &src);   // set *this to any vector 
                                                        // normal to src 

    // Matrix operations
    Vec3		rotate(const Matrix4f&) const;
    Vec3		rotate(const Affine4f&) const;

    Vec3		transform(const Matrix4f&) const;
    Vec3		transform(const Affine4f&) const;

    Vec3		inverseRotate(const Matrix4f&) const;
    Vec3		inverseTransform(const Matrix4f&) const;

    // constants to make code smaller when passing addresses
    static const Vec3&  origin();
    static const Vec3&  xAxis();
    static const Vec3&  yAxis();
    static const Vec3&  zAxis();
};

// Accessors
template<class T> inline T&
Vec3<T>::operator[](unsigned int i)
{
    return (&x)[i];
}

template<class T> inline const T&
Vec3<T>::operator[](unsigned int i) const
{
    return (&x)[i];
}

// Assignment operators
template<class T> inline Vec3<T>&
Vec3<T>::operator+=(const Vec3<T>& v)
{
    x += v.x;
    y += v.y;
    z += v.z;
    return *this;
}

template<class T> inline Vec3<T>&
Vec3<T>::operator-=(const Vec3<T>& v)
{
    x -= v.x;
    y -= v.y;
    z -= v.z;
    return *this;
}

template<class T> inline Vec3<T>&
Vec3<T>::operator*=(const Vec3<T>& v)
{
    x *= v.x;
    y *= v.y;
    z *= v.z;
    return *this;
}

template<class T> inline Vec3<T>&
Vec3<T>::operator/=(const Vec3<T>& v)
{
    x /= v.x;
    y /= v.y;
    z /= v.z;
    return *this;
}

template<class T> inline Vec3<T>&
Vec3<T>::operator*=(T v)
{
    x *= v;
    y *= v;
    z *= v;
    return *this;
}

inline Vec3<double>&
Vec3<double>::operator/=(double v)
{
    double r = 1.0 / v;
    
    x *= r;
    y *= r;
    z *= r;
    return *this;
}

inline Vec3<float>&
Vec3<float>::operator/=(float v)
{
    float r = 1.0f / v;
    
    x *= r;
    y *= r;
    z *= r;
    return *this;
}

template<class T> inline Vec3<T>&
Vec3<T>::operator/=(T v)
{
    x /= v;
    y /= v;
    z /= v;
    return *this;
}

// Unary operators
template<class T> inline Vec3<T>
operator+(const Vec3<T>& v)
{
    return v;
}

template<class T> inline Vec3<T>
operator-(const Vec3<T>& v)
{
    return Vec3<T>(-v.x, -v.y, -v.z);
}

// Binary operators
template<class T> inline Vec3<T>
operator+(const Vec3<T>& v1, const Vec3<T>& v2)
{
    return Vec3<T>(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}

template<class T> inline
Vec3<T> &Vec3<T>::sub(const Vec3<T> &v1, const Vec3<T> &v2)
{
    x = v1.x - v2.x;
    y = v1.y - v2.y;
    z = v1.z - v2.z;
    return(*this);
}

template<class T> inline
Vec3<T> &Vec3<T>::negate()
{
    x = -x;
    y = -y;
    z = -z;
    return(*this);
}

template<class T> inline Vec3<T>
operator-(const Vec3<T>& v1, const Vec3<T>& v2)
{
    Vec3<T> temp;
    temp.sub(v1,v2);
    return(temp);
}

template<class T> inline Vec3<T>
operator*(const Vec3<T>& v1, const Vec3<T>& v2)
{
    return Vec3<T>(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
}

template<class T> inline Vec3<T>
operator*(const Vec3<T>& v, T s)
{
    return Vec3<T>(v.x * s, v.y * s, v.z * s);
}

template<class T> inline Vec3<T>
operator*(T s, const Vec3<T>& v)
{
    return Vec3<T>(v.x * s, v.y * s, v.z * s);
}

template<class T> inline Vec3<T>
operator*(const Vec3<T>& v, const Matrix4f& m)
{
    return v.transform(m);
}

template<class T> inline Vec3<T>
operator*(const Vec3<T>& v, const Matrix3f& m)
{
    return Vec3<T>(v[0]*m[0][0] + v[1]*m[1][0] + v[2]*m[2][0],
		      v[0]*m[0][1] + v[1]*m[1][1] + v[2]*m[2][1],
		      v[0]*m[0][2] + v[1]*m[1][2] + v[2]*m[2][2]);
}

template<class T> inline Vec3<T>
operator*(const Matrix3f& m, const Vec3<T>& v)
{
    return Vec3<T>(v[0]*m[0][0] + v[1]*m[0][1] + v[2]*m[0][2],
		      v[0]*m[1][0] + v[1]*m[1][1] + v[2]*m[1][2],
		      v[0]*m[2][0] + v[1]*m[2][1] + v[2]*m[2][2]);
}

template<class T> inline Vec3<T>
operator/(const Vec3<T>& v1, const Vec3<T>& v2)
{
    return Vec3<T>(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z);
}

template<class T> inline Vec3<T>
operator/(const Vec3<T>& v, T s)
{
    return Vec3<T>(v.x / s, v.y / s, v.z / s);
}

template<class T> inline Vec3<T>
operator/(T s, const Vec3<T>& v)
{
    return Vec3<T>(s / v.x, s / v.y, s / v.z);
}

template<class T> inline Vec3<T>
operator/(const Vec3<T>& v, const Matrix4f& m)
{
    return v.inverseTransform(m);
}

template<class T> inline Vec3<T>
operator^(const Vec3<T>& v1, const Vec3<T>& v2)
{
    return cross(v1, v2);
}

// Testing
template<class T> bool
operator<(const Vec3<T>& v1, const Vec3<T>& v2)
{
    if (v1.x < v2.x) return true;
    if (v1.x > v2.x) return false;
    if (v1.y < v2.y) return true;
    if (v1.y > v2.y) return false;
    return v1.z < v2.z;
}

template<class T> bool
operator<=(const Vec3<T>& v1, const Vec3<T>& v2)
{
    if (v1.x < v2.x) return true;
    if (v1.x > v2.x) return false;
    if (v1.y < v2.y) return true;
    if (v1.y > v2.y) return false;
    return v1.z <= v2.z;
}

inline bool
operator==(const Vec3<float>& v1, const Vec3<float>& v2)
{
    //return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;

    float a = v1.x - v2.x;
    float b = v1.y - v2.y;
    float c = v1.z - v2.z;
    
    return (floatToIntBits(a) == 0 &&
	    floatToIntBits(b) == 0 &&
	    floatToIntBits(c) == 0);
}

template<class T> bool Vec3<T>::isZero() const
{
    return x == 0 && y == 0 && z == 0;
}

template<class T> inline bool
operator==(const Vec3<T>& v1, const Vec3<T>& v2)
{
    return v1.x == v2.x && v1.y == v2.y && v1.z == v2.z;
}

template<class T> inline bool
operator!=(const Vec3<T>& v1, const Vec3<T>& v2)
{
    return !(v1 == v2);
}

template<class T> inline int
Vec3<T>::operator==(const T& i) const
{
    return x == i && y == i && z == i;
}

inline bool
Vec3<double>::equal(const Vec3<double>& v, double e) const
{
    if (fabs(x - v.x) < e &&
	fabs(y - v.y) < e &&
	fabs(z - v.z) < e)
	return true;
    else
	return false;
    
}

template<class T> bool
Vec3<T>::equal(const Vec3<T>& v, T e) const
{
    return (equals(x, v.x, e) && equals(y, v.y, e) && equals(z, v.z, e));
}

template<class T> inline T
Vec3<T>::lengthSquared() const
{
    return(x * x + y * y + z * z);
}

inline double
Vec3<double>::modulus() const
{
    double mod = x * x + y * y + z * z;
    
    if (mod > 0) mod = sqrt(mod);

    return mod;
}

inline float
Vec3<float>::modulus() const
{
    float mod = x * x + y * y + z * z;
    
    if (mod > 0) mod = sqrtf(mod);

    return mod;
}


template<class T> T
Vec3<T>::modulus() const
{
    T mod = x * x + y * y + z * z;
    
    if (mod > 0) mod = (T)sqrtf(mod);

    return mod;
}

template<class T> T
Vec3<T>::distanceToSquared(const Vec3<T> &there) const
{
    T dx, dy, dz;

    dx = there.x - x;
    dx *= dx;
    dy = there.y - y;
    dx += dy * dy;
    dz = there.z - z;
    return(dx + dz * dz);
}

inline double 
Vec3<double>::distanceTo(const Vec3<double> &there) const
{
    double dx = distanceToSquared(there);
    if(dx > 0.0)
        dx = sqrt(dx);
    return(dx);
}

template<class T> T
Vec3<T>::distanceTo(const Vec3<T> &there) const
{
    T dx = distanceToSquared(there);
    if(dx > (T)0)
        dx = (T)sqrtf(dx);
    return(dx);
}

// Modifying
template<class T> inline void
Vec3<T>::zero()
{
    x = y = z = 0;
}

inline void
Vec3<double>::normalize()
{
    double inv_mod = invSqrt((x * x) + (y * y) + (z * z));

    x *= inv_mod;
    y *= inv_mod;
    z *= inv_mod;
}

inline void
Vec3<float>::normalize()
{
    float inv_mod = fastInvSqrtf((x * x) + (y * y) + (z * z));

    x *= inv_mod;
    y *= inv_mod;
    z *= inv_mod;
}

template<class T> void
Vec3<T>::normalize()
{
    float inv_mod = 1 / sqrt((x * x) + (y * y) + (z * z));

    x = (T)(x * inv_mod);
    y = (T)(y * inv_mod);
    z = (T)(z * inv_mod);
}

inline Vec3<double>&
Vec3<double>::scaleTo(double newlen)
{
    double inv_mod = invSqrt((x * x) + (y * y) + (z * z));

    inv_mod *= newlen;
    x = (double)(x * inv_mod);
    y = (double)(y * inv_mod);
    z = (double)(z * inv_mod);
    return(*this);
}

template<class T> inline
Vec3<T> &Vec3<T>::scaleTo(T newlen)
{
    float inv_mod = fastInvSqrtf((x * x) + (y * y) + (z * z));

    inv_mod *= newlen;
    x = (T)(x * inv_mod);
    y = (T)(y * inv_mod);
    z = (T)(z * inv_mod);
    return(*this);
}

template<class T> void
Vec3<T>::clamp(T min, T max)
{
    if (x < min)
        x = min;
    if (y < min)
        y = min;
    if (z < min)
        z = min;

    if (x > max)
        x = max;
    if (y > max)
        y = max;
    if (z > max)
        z = max;
}

// Geometric operations
template<class T> inline T
dot(const Vec3<T>& v1, const Vec3<T>& v2)
{
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}

template<class T> inline T
Vec3<T>::dot(const Vec3& v2) const
{
    return x * v2.x + y * v2.y + z * v2.z;
}

template<class T> inline Vec3<T>&
Vec3<T>::cross(const Vec3& v1, const Vec3& v2)
{
    T ax, ay, az;
    T bx, by, bz;

    ax = v1.x; ay = v1.y; az = v1.z;
    bx = v2.x; by = v2.y; bz = v2.z;

    x = ay * bz - az * by;
    y = az * bx - ax * bz;
    z = ax * by - ay * bx;

    return(*this);
}

template<class T> inline Vec3<T> 
cross(const Vec3<T>& v1, const Vec3<T>& v2)
{
    Vec3<T> ret;
    ret.cross(v1,v2);
    return(ret);
}

template<class T> Vec3<T>
reflect(const Vec3<T>& n, const Vec3<T>& i)
{
    /*
     * If the incident vector is I, the normal is N, then the reflected vector
     * R is given by:
     *
     *		R = I + 2 * cos theta * N
     *
     * where theta is the angle between -I and N.
     * 
     * This is due to the fact that I + R is the same vector as 2 * I + 2 *
     * cos theta * N (proof by geometry).
     */
    T c = -dot(n, i);
    Vec3<T> r = i + (2 * c) * n;
    return r;
}

template<class T> Vec3<T>
refract(const Vec3<T>& n, const Vec3<T>& i, T indexRatio)
{
    /*
     * If the incident vector is I, the normal is N and the refractive
     * index of the two surfaces is n1 and n2, then the refracted
     * vector R is given by:
     *
     *		R = (n1/n2)*I - (cos refracted + (n1/n2) * (I . N)) * N
     *
     * where 'refracted' is the angle of the refracted ray which is
     * derived using the formula:
     *
     *		sin refracted = (n1/n2) * sin incident
     */
    T ndoti = dot(n, i); 
    T cosIncident = -ndoti;
    T sinIncident = sqrtf(1 - cosIncident * cosIncident);
    T sinTransmitted = indexRatio * sinIncident;
    T cosTransmitted = sqrtf(1 - sinTransmitted * sinTransmitted);
    return (indexRatio * i
	    - ((cosTransmitted + indexRatio * ndoti) * n));
}

template<class T> Vec3<T>
interpolate(T mul, const Vec3<T>& v1, const Vec3<T>& v2)
{
    return v1 + ((v2 - v1) * mul);
}

template<class T> void
Vec3<T>::setNormalTo(const Vec3 &d)
//  set this to a vector normal to d
{
    x = 0;

    if(d.z == 0)
    {
        if(d.y == 0)
        {
            y = 0;
            z = 1;
            return;
        }
    }
    else if(d.y == 0)
    {
        y = 1;
        z = 0;
        return;
    }
 
    T n_fix = 1 + ((d.z * d.z) / (d.y * d.y));
    z = (T)sqrt(1 / n_fix);
    y = -(z * (d.z / d.y));
    return;
}

// Matrix operations

template<class T> Vec3<T>
Vec3<T>::transform(const Matrix4f& m) const
{
    return Vec3<T>(x * m[0][0] + y * m[1][0] + z * m[2][0] + m[3][0],
		   x * m[0][1] + y * m[1][1] + z * m[2][1] + m[3][1],
		   x * m[0][2] + y * m[1][2] + z * m[2][2] + m[3][2]);
}

template<class T> Vec3<T>
Vec3<T>::transform(const Affine4f& m) const
{
    Vec3<T> ret;
    m.transformTo(ret,*this);
    return(ret);
}

template<class T> Vec3<T>
Vec3<T>::rotate(const Matrix4f& m) const
{
    return Vec3<T>(x * m[0][0] + y * m[1][0] + z * m[2][0],
		   x * m[0][1] + y * m[1][1] + z * m[2][1],
		   x * m[0][2] + y * m[1][2] + z * m[2][2]);
}

template<class T> Vec3<T>
Vec3<T>::rotate(const Affine4f& m) const
{
    Vec3<T> ret;
    m.rotateTo(ret,*this);
    return(ret);
}

template<class T> Vec3<T>
Vec3<T>::inverseTransform(const Matrix4f& m) const
{
    if (m.flags == m.Identity) {
	return *this;
    } else if (m.flags <= (m.Translate | m.Rotate)) {
	T tx = x, ty = y, tz = z;
	tx -= m[3][0]; ty -= m[3][1]; tz -= m[3][2];
	return Vec3<T>(tx * m[0][0] + ty * m[0][1] + tz * m[0][2],
			  tx * m[1][0] + ty * m[1][1] + tz * m[1][2],
			  tx * m[2][0] + ty * m[2][1] + tz * m[2][2]);
    } else {
	Matrix4f invM; invM.invert(m);
	return transform(invM);
    }
}

template<class T> Vec3<T>
Vec3<T>::inverseRotate(const Matrix4f& m) const
{
    if (m.flags == m.Identity) {
	return *this;
    } else if (m.flags <= (m.Translate | m.Rotate)) {
	return Vec3<T>(x * m[0][0] + y * m[0][1] + z * m[0][2],
			  x * m[1][0] + y * m[1][1] + z * m[1][2],
			  x * m[2][0] + y * m[2][1] + z * m[2][2]);
    } else {
	Matrix4f invM; invM.invert(m);
	return rotate(invM);
    }
}

// constants

template<class T> inline const Vec3<T>&
Vec3<T>::origin()
{
    static const Vec3<T> val(0,0,0);

    return(val);
}

template<class T> inline const Vec3<T>&
Vec3<T>::xAxis()
{
    static const Vec3<T> val((T)1,0,0);

    return(val);
}

template<class T> inline const Vec3<T>&
Vec3<T>::yAxis()
{
    static const Vec3<T> val(0,(T)1,0);

    return(val);
}

template<class T> inline const Vec3<T>&
Vec3<T>::zAxis()
{
    static const Vec3<T> val(0,0,(T)1);

    return(val);
}

// Instantiate Vector types
typedef Vec3<float>		Vec3f;
typedef Vec3<double>		Vec3d;
typedef Vec3<short>		Vec3s;
typedef Vec3<int>		Vec3i;
typedef Vec3<unsigned char>	Vec3b;
typedef Vec3<unsigned int>	Vec3ui;

MATHS_END

#endif

// Local Variables:
// mode: c++
// End:
