/*-
 * 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: vec4.h,v 1.19 2000/04/20 16:21:58 n_hibma Exp $
 */

#ifndef __vec4_h__
#define __vec4_h__

MATHS_BEGIN

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

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

			Vec4() {}
			Vec4(const Vec4& v)
			    : x(v.x), y(v.y), z(v.z), w(v.w) {}
			Vec4(T tx, T ty, T tz, T tw)
			    : x(tx), y(ty), z(tz), w(tw) {}
			Vec4(const Vec2<T>& v)
			    : x(v.x), y(v.y), z(0), w(1) {}
			Vec4(const Vec3<T>& v)
			    : x(v.x), y(v.y), z(v.z), w(1) {}
    
    T&			operator[](unsigned int i) { return (&x)[i]; }
    const T&		operator[](unsigned int i) const { return (&x)[i]; }

    // Operators
    Vec4&               operator*=(T v)
                        {
                            x *= v;
                            y *= v;
                            z *= v;
                            w *= v;
                            return *this;
                        }
    Vec4                operator-() const { return Vec4(-x, -y, -z, -w); }

    // Binary operators
    int		operator==(const Vec4<T>& v) const;
    int		operator!=(const Vec4<T>& v) const 
                                { return !(*this == v); }

    // Matrix operations
    Vec4		transform(const Matrix4f&) const;

    // Testing
    T			modulus() const;
    bool                equal(const Vec4& v, T e = Epsilon) const;

    // Features
    void                normalize();
};

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

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

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

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

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

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

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

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

inline int
Vec4<float>::operator==(const Vec4<float>& v) const
{
    float a = x - v.x;
    float b = y - v.y;
    float c = z - v.z;
    float d = w - v.w;
    
    return (floatToIntBits(a) == 0 &&
	    floatToIntBits(b) == 0 &&
	    floatToIntBits(c) == 0 &&
	    floatToIntBits(d) == 0);
}

template<class T> int
Vec4<T>::operator==(const Vec4<T>& v) const
{
    return x == v.x && y == v.y && z == v.z && w == v.w;
}

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

inline float
Vec4<float>::modulus() const
{
    return sqrtf(x*x + y*y + z*z + w*w);
}

template<class T> T
Vec4<T>::modulus() const
{
    return (T)sqrt(x*x + y*y + z*z + w*w);
}

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

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

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

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

template<class T> void
Vec4<T>::normalize()
{
    double inv_mod = 1.0f / sqrtf(x*x + y*y + z*z + w*w);

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

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

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

inline bool
Vec4<float>::equal(const Vec4<float>& v, float e) const
{
    if (fabsf(x - v.x) < e &&
	fabsf(y - v.y) < e &&
	fabsf(z - v.z) < e &&
        fabsf(w - v.w) < e)
	return true;
    else
	return false;
}

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

// Instantiate Vector types
typedef Vec4<float>		Vec4f;
typedef Vec4<double>		Vec4d;
typedef Vec4<short>		Vec4s;
typedef Vec4<int>		Vec4i;
typedef Vec4<unsigned char>	Vec4b;
typedef Vec4<unsigned int>	Vec4ui;

MATHS_END

#endif

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