/*-
 * 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: matrix4.h,v 1.16 2000/04/20 16:21:57 n_hibma Exp $
 */

#ifndef __matrix4_h__
#define __matrix4_h__

MATHS_BEGIN

struct Affine4f;

struct EXPORT_QMATHS Matrix4f: public TransformFlags
{
    struct Vec4x4
    {
	float		varray_[4][4];
	inline operator Vec4f*()
	    { return (Vec4f*) varray_; }
	inline operator const Vec4f*() const
	    { return (const Vec4f*) varray_; }
    };

			Matrix4f() {}
			Matrix4f(const Matrix4f &src) 
                            { set(src); }
    			Matrix4f(const Affine4f &src) 
                            { set(src); }
    
    unsigned int	flags;	// bitset of Flags

    Vec4x4 m;
   
    // Flags inlines

    unsigned int        getflags() const                { return(flags); }
    unsigned int        getflags(unsigned int f) const  { return(flags & f); }
    void                setflags(unsigned int f)        { flags = f; }
    void                addflags(unsigned int f)        { flags |= f; }
    void                clearflags(unsigned int f)      { flags &= (~f); }
 

    int                 isIdentity() const
                                { return(flags == Identity); }
    int                 isTranslated() const 
                                { return(flags & (Translate)); }
    int                 isRotated() const 
                                { return(flags & (Rotate | Shear)); }
    int                 isScaled() const
                                { return(flags & (Scale | UniformScale | Shear)); }

    void                buildFlags(); // set flags to represent data (unimplemented) 

    // Assignment

    void		set(const Matrix4f &src);

    Matrix4f &          operator=(const Matrix4f &src) 
                                { set(src); return(*this); }
    
    void		set(const Affine4f &src);

    Matrix4f &          operator=(const Affine4f &src) 
                                { set(src); return(*this); }

    // Accessors
   
    Vec4f&		operator[](unsigned int i) { return m[i]; }
    const Vec4f&	operator[](unsigned int i) const { return m[i]; }

    const Vec3f&	up() const
			    { return *reinterpret_cast<const Vec3f*>(&m.varray_[1][0]); }
    const Vec3f&	direction() const
			    { return *reinterpret_cast<const Vec3f*>(&m.varray_[2][0]); }
    const Vec3f&	position() const
			    { return *reinterpret_cast<const Vec3f*>(&m.varray_[3][0]); }
    const Vec3f&	side() const
                            { return *reinterpret_cast<const Vec3f*>(&m.varray_[0][0]); }

    // Modifiers

    void                clearW()  // Clear W terms to affine values.
                            { 
                                m.varray_[0][3] = 0;
                                m.varray_[1][3] = 0;
                                m.varray_[2][3] = 0;
                                m.varray_[3][3] = 1;
                                clearflags(General);
                            }

    void		setIdentity();

    // set rotation leaving translation unaltered
    void                setRotation(const Vec3f &axis, float angle);
    // set rotation leaving translation unaltered
    void                setRotation(const Quat4f &quat);    
    // set rotation leaving translation unaltered
    void		setRotation(const Vec3f &dir, const Vec3f &up);
    // set rotation leaving translation unaltered
    void		setRotation(const Matrix3f&);

    // archaic ?? *****
    void		setQuaternion(const Quat4f& q) { setRotation(q); }
    
    
    void		position(const Vec3f&);
    void                scale(float);
    
    // Arithmetic
    void		product(const Matrix4f &a, const Matrix4f &b);
    void                invert(const Matrix4f &from);
    void                invertOrthonormal(const Matrix4f &from);
    void                invertAffine(const Matrix4f &from);
    void		inverseProduct(const Matrix4f &a, const Matrix4f &ib);
    void		transpose(const Matrix4f &from);
    
    
    Matrix4f		operator  *(const Matrix4f& b) const
                            {
                                Matrix4f temp;
                                temp.product(*this,b);
                                return(temp);
                            }
    
    Matrix4f            &operator *=(const Matrix4f &b)
                            { product(Matrix4f(*this),b); return(*this); }

    Matrix4f		inverseProduct(const Matrix4f& m) const
			    {
				Matrix4f temp;
				temp.inverseProduct(*this, m);
				return(temp);
			    }
    
    Matrix4f		invert() const
                            { Matrix4f temp; temp.invert(*this); return(temp); }

    Matrix4f		transpose() const
                            { Matrix4f temp; temp.transpose(*this); return(temp); }
};

MATHS_END

#endif

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