/*-
 * 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: quat4.h,v 1.15 2000/05/02 13:31:22 nps Exp $
 */

#ifndef __quat_h__
#define __quat_h__

MATHS_BEGIN

struct Matrix4f;

struct EXPORT_QMATHS Quat4f : public Vec4f
{
			Quat4f() {}
			Quat4f(const Quat4f& q)
			    : Vec4f(q) {}
			Quat4f(const Vec4f& v)
			    : Vec4f(v) {}
			Quat4f(float x1, float y1, float z1, float w1)
			    : Vec4f(x1, y1, z1, w1) {}
			Quat4f(const Vec3f &axis, float angle)
                            { setRotation(axis,angle); }
			// axis scaled by angle
			Quat4f(const Vec3f&);
			// rotation matrix
			Quat4f(const Matrix3f &m)
                            { setMatrix(m); }
			Quat4f(const Vec3f &dir, const Vec3f &up)
                            { setRotation(dir,up); }
                        Quat4f(const Matrix4f &m, bool normalise=false);

    // Features
    void		setIdentity();
    void                setRotation(const Vec3f &axis, float angle);
    void                setRotation(const Vec3f &direction, const Vec3f &up);
    void		setMatrix(const Matrix3f &m, bool normalise=false);
    void                addRotation(const Vec3f &axis, float angle);
    void                random();
    bool                isIdentity() 
                            { return(x == 0 && w == 1); } // close enough




    void                mult(const Quat4f &q);
    void                mult(const Quat4f &a, const Quat4f &b);
    void    	        getDirection(Vec3f &dir) const;
    void    	        getUpVector(Vec3f &up) const;
    void                getAxis(Vec3f &axis) const;

    Quat4f &		operator*=(const Quat4f &q)
                            { mult(q); return(*this); }

    friend Quat4f operator*(const Quat4f &a, const Quat4f &b)
                            {  Quat4f temp; temp.mult(a,b); return(temp); }    
    Vec3f		up() const
                            { Vec3f v; getUpVector(v); return(v); }

    Vec3f		direction() const
                            { Vec3f v; getDirection(v); return(v); }

    Quat4f              invert() const;

    Vec3f               axis() const
                            { Vec3f v; getAxis(v); return(v); }
    
    float               angle() const;
    bool                equal(const Quat4f& v, float e = Epsilon) const;
                            

    friend EXPORT_QMATHS Quat4f interpolate(float t,
					   const Quat4f&,
					   const Quat4f&);
protected:

    inline Vec3f&	vec3()          { return(*(Vec3f *)&x); }
    inline const Vec3f&	vec3() const    { return(*(const Vec3f *)&x); }

};




MATHS_END

#endif

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