/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#ifndef __VECTOR_HPP_
#define __VECTOR_HPP_

#include "math/num_type.hh"
#include 

#ifdef _WINDOWS
//#define G1_WIN32_VECTOR_ASM
#endif


template 
class i4_vector3_template
{
public:
  Coord x,y,z;

  Coord& operator()(int pos) const { return ((Coord*)&x)[pos]; }
  Coord& operator[](int pos) const { return ((Coord*)&x)[pos]; }

  i4_vector3_template() {}
  i4_vector3_template(const i4_vector3_template& p) : x(p.x), y(p.y), z(p.z) {}
  i4_vector3_template(Coord _x,Coord _y,Coord _z) : x(_x),y(_y),z(_z) {}
  i4_vector3_template& set(Coord px,Coord py,Coord pz)
  {
    x = px;
    y = py;
    z = pz;

    return *this;
  }
  i4_vector3_template& operator=(const i4_vector3_template& p)
  {
    x = p.x;
    y = p.y;
    z = p.z;

    return *this;
  }
  
  i4_vector3_template& operator+=(const i4_vector3_template& b)
  {
    x += b.x;
    y += b.y;
    z += b.z;

    return *this;
  }
  i4_vector3_template& operator-=(const i4_vector3_template& b)
  {
    x -= b.x;
    y -= b.y;
    z -= b.z;

    return *this;
  }

  i4_vector3_template& operator*=(Coord b)
  {
    x *= b;
    y *= b;
    z *= b;

    return *this;
  }

  i4_vector3_template operator*(Coord b)
  {
    i4_vector3_template tmp;
    tmp.x = x * b;
    tmp.y = y * b;
    tmp.z = z * b;

    return tmp;
  }


  i4_vector3_template operator+(Coord b)
  {
    i4_vector3_template tmp;
    tmp.x = x + b;
    tmp.y = y + b;
    tmp.z = z + b;

    return tmp;
  }

  i4_vector3_template operator+(i4_vector3_template v)
  {
    i4_vector3_template tmp;
    tmp.x = x + v.x;
    tmp.y = y + v.y;
    tmp.z = z + v.z;

    return tmp;
  }

  i4_vector3_template operator*(i4_vector3_template v)
  {
    i4_vector3_template tmp;
    tmp.x = x * v.x;
    tmp.y = y * v.y;
    tmp.z = z * v.z;

    return tmp;
  }

  i4_vector3_template& operator/=(Coord b)
  {
    x /= b;
    y /= b;
    z /= b;

    return *this;
  }

  i4_vector3_template& interpolate(const i4_vector3_template& from, const i4_vector3_template& to, 
                                   i4_float ratio)
  {
    x = i4_interpolate(from.x,to.x,ratio);
    y = i4_interpolate(from.y,to.y,ratio);
    z = i4_interpolate(from.z,to.z,ratio);
    return *this;
  }
  
  Coord length() const
  {
    return (Coord)sqrt(dot(*this));
  }
  void normalize()
  {
    *this /= length();
  }

  i4_vector3_template& reverse()
  {
    x=-x; y=-y; z=-z;

    return *this;
  }

  Coord dot(const i4_vector3_template& b) const
  {
#ifdef G1_WIN32_VECTOR_ASM
    i4_float dotret;
    _asm
    {
      mov     ecx, b
      mov     eax, this

      ;optimized dot product; 15 cycles
      fld dword ptr   [eax+0]     ;starts & ends on cycle 0
      fmul dword ptr  [ecx+0]     ;starts on cycle 1
      fld dword ptr   [eax+4]     ;starts & ends on cycle 2
      fmul dword ptr  [ecx+4]     ;starts on cycle 3
      fld dword ptr   [eax+8]     ;starts & ends on cycle 4
      fmul dword ptr  [ecx+8]     ;starts on cycle 5
      fxch            st(1)       ;no cost
      faddp           st(2),st(0) ;starts on cycle 6, stalls for cycles 7-8
      faddp           st(1),st(0) ;starts on cycle 9, stalls for cycles 10-12
      fstp dword ptr  [dotret]    ;starts on cycle 13, ends on cycle 14
    }
    return dotret;
#else
    return x*b.x + y*b.y + z*b.z;
#endif
  }

    i4_vector3_template& cross(const i4_vector3_template& a, 
                                    const i4_vector3_template& b)
  {
#ifdef UNFINISHED_WINDOWS
    _asm
    {
      mov     eax,this
      mov     ecx,a
      mov     edx,b

      ;optimized cross product; 22 cycles
      fld dword ptr   [ecx+4]     ;starts & ends on cycle 0
      fmul dword ptr  [edx+8]     ;starts on cycle 1       
      fld dword ptr   [ecx+8]     ;starts & ends on cycle 2
      fmul dword ptr  [edx+0]     ;starts on cycle 3       
      fld dword ptr   [ecx+0]     ;starts & ends on cycle 4
      fmul dword ptr  [edx+4]     ;starts on cycle 5       
      fld dword ptr   [ecx+8]     ;starts & ends on cycle 6
      fmul dword ptr  [edx+4]     ;starts on cycle 7       
      fld dword ptr   [ecx+0]     ;starts & ends on cycle 8
      fmul dword ptr  [edx+8]     ;starts on cycle 9         
      fld dword ptr   [ecx+4]     ;starts & ends on cycle 10 
      fmul dword ptr  [edx+0]     ;starts on cycle 11        
      fxch            st(2)       ;no cost                   
      fsubrp          st(5),st(0) ;starts on cycle 12        
      fsubrp          st(3),st(0) ;starts on cycle 13        
      fsubrp          st(1),st(0) ;starts on cycle 14        
      fxch            st(2)       ;no cost, stalls for cycle 15
      fstp dword ptr  [eax+0]     ;starts on cycle 16, ends on cycle 17  
      fstp dword ptr  [eax+4]     ;starts on cycle 18, ends on cycle 19
      fstp dword ptr  [eax+8]     ;starts on cycle 20, ends on cycle 21
    }
#else
    x = a.y*b.z - a.z*b.y;
    y = a.z*b.x - a.x*b.z;
    z = a.x*b.y - a.y*b.x;
#endif
    return *this;
  }
};


class i4_2d_vector
{
public:
  i4_float x,y;

  i4_2d_vector() { ; }

  i4_2d_vector(i4_float x, i4_float y) : x(x), y(y) {}

  i4_float length() const { return sqrt(x*x+y*y); }
  i4_float dot(const i4_2d_vector &b)  { return x*b.x + y*b.y; }
  i4_float perp_dot(const i4_2d_vector &b)  { return x*b.y-y*b.x; }

  i4_2d_vector& operator-=(const i4_2d_vector& b) { x-=b.x; y-=b.y; return *this; }
  i4_2d_vector& operator+=(const i4_2d_vector& b) { x+=b.x; y+=b.y; return *this; }
  i4_2d_vector& operator*=(const i4_2d_vector& b) { x*=b.x; y*=b.y; return *this; }
  i4_2d_vector& operator/=(const i4_2d_vector& b) { x/=b.x; y/=b.y; return *this; }
  
  i4_2d_vector operator+(const i4_2d_vector& b) { return i4_2d_vector(x+b.x, y+b.y); }
  i4_2d_vector operator-(const i4_2d_vector& b) { return i4_2d_vector(x-b.x, y-b.y); }
  i4_2d_vector operator*(const i4_2d_vector& b) { return i4_2d_vector(x*b.x, y*b.y); }
  i4_2d_vector operator/(const i4_2d_vector& b) { return i4_2d_vector(x*b.x, y*b.y); }

  void normalize() 
  {
    i4_float ool=1.0/length();
    x*=ool;
    y*=ool;
  }
};


typedef i4_vector3_template  i4_3d_vector;

#endif