/*==========================================================================
 *                                                                         *
 *  Copyright (C) 2001 Dymchenko L.A.                                      *
 *                                                                         *
 *  VirtualRay (Spherical Engine) additional header file                   *
 *                                                                         *
 ***************************************************************************/


#ifndef LinAlgh
#define LinAlgh


class rmatrt
{
    public:

    rnumt m11,m12,m13,m21,m22,m23,m31,m32,m33;

    inline rvectort transform(const rvectort& v) const;
    inline rvectort reconversion(const rvectort& v) const;

    void normalizecolumns();

    inline void transpose();
  inline rmatrt gettransposed() const;
    void inverse();

    inline rvectort& v1();
    inline rvectort& v2();
    inline rvectort& v3();
  inline rvectort v(i32 index) const;

    rmatrt() {};
    inline rmatrt(const rvectort& v1, const rvectort& v2, const rvectort& v3);
};
typedef rmatrt* rmatrpt;


class basisobj: public rmatrt
{
    public:

    void rotatex(rnumt phi);
    inline void rotatex(rnumt cosphi, rnumt sinphi);
    void rotatey(rnumt phi);
    inline void rotatey(rnumt cosphi, rnumt sinphi);
    void rotatez(rnumt phi);
    inline void rotatez(rnumt cosphi, rnumt sinphi);


    void setrx(rnumt phi);
    inline void setrx(rnumt cosphi, rnumt sinphi);
    void setry(rnumt phi);
    inline void setry(rnumt cosphi, rnumt sinphi);
    void setrz(rnumt phi);
    inline void setrz(rnumt cosphi, rnumt sinphi);


  void setdir(const rvectort& dirv, rnumt phi);


  inline void operator = (const rmatrt& m);
    inline void operator = (const float*  mp);

    inline void sete();

    basisobj() {};
    inline basisobj(const rvectort& v1, const rvectort& v2, const rvectort& v3);
};

typedef basisobj* basisobjpt;

//////////////////////////////////////////////////////////////////////////

inline rvectort rmatrt::transform(const rvectort& v) const
{
    rvectort newv;

    newv.x=m11*v.x+m21*v.y+m31*v.z;
    newv.y=m12*v.x+m22*v.y+m32*v.z;
    newv.z=m13*v.x+m23*v.y+m33*v.z;

    return newv;
}

inline rvectort rmatrt::reconversion(const rvectort& v) const
{
    rvectort newv;

    newv.x=m11*v.x+m12*v.y+m13*v.z;
    newv.y=m21*v.x+m22*v.y+m23*v.z;
    newv.z=m31*v.x+m32*v.y+m33*v.z;

    return newv;
}


inline void rmatrt::transpose()
{
    rnumt m;
    
    m=m12;
    m12=m21;
    m21=m;

    m=m13;
    m13=m31;
    m31=m;

    m=m23;
    m23=m32;
    m32=m;
}


inline rmatrt rmatrt::gettransposed() const
{
  rmatrt m;

  m.m11=m11;
  m.m12=m21;
  m.m13=m31;

  m.m21=m12;
  m.m22=m22;
  m.m23=m32;

  m.m31=m13;
  m.m32=m23;
  m.m33=m33;

  return m;
}


inline rmatrt::rmatrt(const rvectort& v1, const rvectort& v2, const rvectort& v3)
{
    m11=v1.x;
    m12=v1.y;
    m13=v1.z;

    m21=v2.x;
    m22=v2.y;
    m23=v2.z;

    m31=v3.x;
    m32=v3.y;
    m33=v3.z;
}


inline void basisobj::rotatex(rnumt cosphi, rnumt sinphi)
{
    rvectort newv2,newv3;


    newv2.x=cosphi*m21+sinphi*m31;
    newv2.y=cosphi*m22+sinphi*m32;
    newv2.z=cosphi*m23+sinphi*m33;

    newv3.x=-sinphi*m21+cosphi*m31;
    newv3.y=-sinphi*m22+cosphi*m32;
    newv3.z=-sinphi*m23+cosphi*m33;


    m21=newv2.x;
    m22=newv2.y;
    m23=newv2.z;

    m31=newv3.x;
    m32=newv3.y;
    m33=newv3.z;
}

inline void basisobj::rotatey(rnumt cosphi, rnumt sinphi)
{
    rvectort newv3,newv1;


    newv3.x=cosphi*m31+sinphi*m11;
    newv3.y=cosphi*m32+sinphi*m12;
    newv3.z=cosphi*m33+sinphi*m13;

    newv1.x=-sinphi*m31+cosphi*m11;
    newv1.y=-sinphi*m32+cosphi*m12;
    newv1.z=-sinphi*m33+cosphi*m13;


    m11=newv1.x;
    m12=newv1.y;
    m13=newv1.z;

    m31=newv3.x;
    m32=newv3.y;
    m33=newv3.z;
}

inline void basisobj::rotatez(rnumt cosphi, rnumt sinphi)
{
    rvectort newv1,newv2;


    newv1.x=cosphi*m11+sinphi*m21;
    newv1.y=cosphi*m12+sinphi*m22;
    newv1.z=cosphi*m13+sinphi*m23;

    newv2.x=-sinphi*m11+cosphi*m21;
    newv2.y=-sinphi*m12+cosphi*m22;
    newv2.z=-sinphi*m13+cosphi*m23;


    m11=newv1.x;
    m12=newv1.y;
    m13=newv1.z;

    m21=newv2.x;
    m22=newv2.y;
    m23=newv2.z;
}


inline void basisobj::setrx(rnumt cosphi, rnumt sinphi)
{
    m11=1;
    m12=0;
    m13=0;

    m21=0;
    m22=cosphi;
    m23=sinphi;

    m31=0;
    m32=-sinphi;
    m33=cosphi;
}

inline void basisobj::setry(rnumt cosphi, rnumt sinphi)
{
    m11=cosphi;
    m12=0;
    m13=-sinphi;

    m21=0;
    m22=1;
    m23=0;

    m31=sinphi;
    m32=0;
    m33=cosphi;
}

inline void basisobj::setrz(rnumt cosphi, rnumt sinphi)
{
    m11=cosphi;
    m12=sinphi;
    m13=0;

    m21=-sinphi;
    m22=cosphi;
    m23=0;

    m31=0;
    m32=0;
    m33=1;
}



inline rvectort& rmatrt::v1() 
{
    return (rvectort&)*((rvectorpt)&m11);
}

inline rvectort& rmatrt::v2()
{
    return (rvectort&)*((rvectorpt)&m21);
}

inline rvectort& rmatrt::v3()
{
    return (rvectort&)*((rvectorpt)&m31);
}

inline rvectort rmatrt::v(i32 index) const
{
  rvectorpt vp;

  vp=((rvectorpt)this)+index;
  return *vp;
}


inline void basisobj::sete()
{
    m11=1.0f;
    m12=0.0f;
    m13=0.0f;

    m21=0.0f;
    m22=1.0f;
    m23=0.0f;

    m31=0.0f;
    m32=0.0f;
    m33=1.0f;
}


inline void basisobj::operator = (const rmatrt& m)
{
    m11=m.m11;
    m12=m.m12;
    m13=m.m13;

    m21=m.m21;
    m22=m.m22;
    m23=m.m23;

    m31=m.m31;
    m32=m.m32;
    m33=m.m33;
}

inline void basisobj::operator = (const float* mp)
{
    m11=mp[0];
    m12=mp[1];
    m13=mp[2];

    m21=mp[3];
    m22=mp[4];
    m23=mp[5];

    m31=mp[6];
    m32=mp[7];
    m33=mp[8];
}

inline basisobj::basisobj(const rvectort& v1, const rvectort& v2, const rvectort& v3)
{
    m11=v1.x;
    m12=v1.y;
    m13=v1.z;

    m21=v2.x;
    m22=v2.y;
    m23=v2.z;

    m31=v3.x;
    m32=v3.y;
    m33=v3.z;
}


inline rvectort operator * (const basisobj& m, const rvectort& v);
inline rvectort operator * (const rvectort& v, const basisobj& m);
inline basisobj operator * (const basisobj m, const rnumt c);
inline basisobj operator * (const rnumt c, const basisobj m);

rmatrt operator * (const rmatrt& a, const rmatrt& b);
inline basisobj operator + (const basisobj& a, const basisobj& b);
inline basisobj& operator += (basisobj& a, const basisobj& b);
inline basisobj operator - (const basisobj& a, const basisobj& b);
inline basisobj& operator -= (basisobj& a, const basisobj& b);
inline basisobj& operator - (basisobj& a);
basisobj operator * (const basisobj& a, const basisobj& b);



inline rvectort operator * (const basisobj& m, const rvectort& v)
{
    rvectort newv;

    newv.x=m.m11*v.x+m.m12*v.y+m.m13*v.z;
    newv.y=m.m21*v.x+m.m22*v.y+m.m23*v.z;
    newv.z=m.m31*v.x+m.m32*v.y+m.m33*v.z;

    return newv;
}

inline rvectort operator * (const rvectort& v, const basisobj& m)
{
    rvectort newv;

    newv.x=m.m11*v.x+m.m12*v.y+m.m13*v.z;
    newv.y=m.m21*v.x+m.m22*v.y+m.m23*v.z;
    newv.z=m.m31*v.x+m.m32*v.y+m.m33*v.z;

    return newv;
}

inline basisobj operator * (const basisobj& m, const rnumt c)
{
    basisobj newm;

    newm.m11=m.m11*c;
    newm.m12=m.m12*c;
    newm.m13=m.m13*c;

    newm.m21=m.m21*c;
    newm.m22=m.m22*c;
    newm.m23=m.m23*c;

    newm.m31=m.m31*c;
    newm.m32=m.m32*c;
    newm.m33=m.m33*c;

    return newm;
}

inline basisobj operator * (const rnumt c, const basisobj& m)
{
    basisobj newm;

    newm.m11=m.m11*c;
    newm.m12=m.m12*c;
    newm.m13=m.m13*c;

    newm.m21=m.m21*c;
    newm.m22=m.m22*c;
    newm.m23=m.m23*c;

    newm.m31=m.m31*c;
    newm.m32=m.m32*c;
    newm.m33=m.m33*c;

    return newm;
}

inline basisobj operator + (const basisobj& a, const basisobj& b)
{
    basisobj c;

    c.m11=a.m11+b.m11;
    c.m12=a.m12+b.m12;
    c.m13=a.m13+b.m13;

    c.m21=a.m21+b.m21;
    c.m22=a.m22+b.m22;
    c.m23=a.m23+b.m23;

    c.m31=a.m31+b.m31;
    c.m32=a.m32+b.m32;
    c.m33=a.m33+b.m33;

    return c;
}

inline basisobj& operator += (basisobj& a, const basisobj& b)
{
    a.m11+=b.m11;
    a.m12+=b.m11;
    a.m13+=b.m11;

    a.m21+=b.m21;
    a.m22+=b.m22;
    a.m23+=b.m23;

    a.m31+=b.m31;
    a.m32+=b.m32;
    a.m33+=b.m33;

    return a;
}

inline basisobj operator - (basisobj& a, const basisobj& b)
{
    basisobj c;

    c.m11=a.m11-b.m11;
    c.m12=a.m12-b.m12;
    c.m13=a.m13-b.m13;

    c.m21=a.m21-b.m21;
    c.m22=a.m22-b.m22;
    c.m23=a.m23-b.m23;

    c.m31=a.m31-b.m31;
    c.m32=a.m32-b.m32;
    c.m33=a.m33-b.m33;

    return c;
}

inline basisobj& operator -= (basisobj& a, const basisobj& b)
{
    a.m11-=b.m11;
    a.m12-=b.m11;
    a.m13-=b.m11;

    a.m21-=b.m21;
    a.m22-=b.m22;
    a.m23-=b.m23;

    a.m31-=b.m31;
    a.m32-=b.m32;
    a.m33-=b.m33;

    return a;
}

inline basisobj& operator - (basisobj& a)
{
    a.m11=-a.m11;
    a.m12=-a.m11;
    a.m13=-a.m11;

    a.m21=-a.m21;
    a.m22=-a.m22;
    a.m23=-a.m23;

    a.m31=-a.m31;
    a.m32=-a.m32;
    a.m33=-a.m33;

    return a;
}


#endif
