//
// ======================================================
//
//       Implementation for Class
//
//          Vec4
//
// ======================================================
//

#include <stdlib.h>
#include <math.h>
#include "matrix.h"
#include "vec4.h"

float Vec4::_float_array[3];
real Vec4::_sqrt_table[SQRT_TABLE_SIZE+2];

//
// =========================================
//
//       Constructors/Destructor:
//
// =========================================
//

// ** inlined **

/*
Vec4::Vec4() {

    _data[0] = _data[1] = _data[2] = _data[3] = 0;
}

Vec4::Vec4(real x, real y, real z, real w) {

    _data[0] = x;
    _data[1] = y;
    _data[2] = z;
    _data[3] = w;
}
*/

Vec4::Vec4(unsigned long l) {

	_data[0] = l & 0x0000FF;
	l = l >> 8;
	_data[1] = l & 0x0000FF;
	l = l >> 8;
	_data[2] = l & 0x0000FF;
	_data[3] = 0;
}

/*
Vec4::Vec4(const Vec4& v) {

    for (int i=0; i<4; i++)
        _data[i] = v._data[i];
}

Vec4::~Vec4() {
}
*/


//
// =======================================
//
//        operator=
//
// =======================================
//

// ** inlined **

/*
Vec4& Vec4::operator=(const Vec4& v) {

    for (int i=0; i<4; i++)
        _data[i] = v._data[i];
    return *this;
}
*/

//
// =======================================
//
//        comparison operators:
//
// =======================================
//

int operator==(const Vec4& v1, const Vec4& v2) {

	for (int i=0; i<4; i++)
		if (v1._data[i] != v2._data[i]) return 0;
	return 1;
}

int operator!=(const Vec4& v1, const Vec4& v2) {

	for (int i=0; i<4; i++)
		if (v1._data[i] != v2._data[i]) return 1;
	return 0;
}

//
// =======================================
//
//        operator<<
//
// =======================================
//

ostream& operator<<(ostream& co, const Vec4& v) {

    co << "[ ";
    for (int i=0; i<4; i++)
	co << v._data[i] << " ";
    co << "]";
    return co;
}

//
// =======================================
//
//      arithmetic operators:
//
// =======================================
//

Vec4 operator+(const Vec4& v1, const Vec4& v2) {

  return Vec4 (v1._data[0] + v2._data[0],
	       v1._data[1] + v2._data[1],
	       v1._data[2] + v2._data[2],
	       v1._data[3] + v2._data[3]);
}

Vec4 operator-(const Vec4& v1, const Vec4& v2) {

  return Vec4 (v1._data[0] - v2._data[0],
	       v1._data[1] - v2._data[1],
	       v1._data[2] - v2._data[2],
	       v1._data[3] - v2._data[3]);
}

Vec4 operator*(Vec4 v, const real& d) {

  v._data[0] *= d;
  v._data[1] *= d;
  v._data[2] *= d;
  v._data[3] *= d;
  return v;
}

Vec4 operator*(const real& d, Vec4 v) {
  v._data[0] *= d;
  v._data[1] *= d;
  v._data[2] *= d;
  v._data[3] *= d;
  return v;
}

/*
Vec4 operator/(Vec4 v, const real& d) {

    for (int i=0; i<4; i++)
        v._data[i] /= d;
    return v;
}
*/

/*
Vec4& Vec4::operator+=(const Vec4& v) {

    for (int i=0; i<4; i++)
	_data[i] += v._data[i];
    return *this;
}
*/

Vec4& Vec4::operator-=(const Vec4& v) {

  _data[0] -= v._data[0];
  _data[1] -= v._data[1];
  _data[2] -= v._data[2];
  _data[3] -= v._data[3];

    return *this;
}

// ** inlined **

/*
Vec4& Vec4::operator*=(const real& d) {

    for (int i=0; i<4; i++)
	_data[i] *= d;
    return *this;
}
*/

Vec4& Vec4::operator*=(const JLmatrix& m) {

    Vec4 v2;

    if (m._size != 4) {
        cerr << "You need to use a 4x4 matrix!" << endl;
        exit(-1);
    }

   for (int i=0; i<4; i++)
        for (int j=0; j<4; j++)
            v2._data[i] += (_data[j] * m._data[i+j*4]); 

    return (*this = v2);
}

//
// =======================================
//
//             DivideByW()
//
//   This functions divides the first
// three coordinates (x, y, and z) by
// the fourth (w).  This converts from
// homogeneous coordinates to 3D space.
//
// =======================================
//

// ** inlined **

/*
Vec4& Vec4::DivideByW() {

    if (!_data[3]) {
	cerr << "Error in DivideByW() -- w = 0!" << endl;
	_data[0] = _data[1] = _data[2] = 0;
    }
    else
	for (int i=0; i<3; i++)
	    _data[i] /= _data[3];

    _data[3] = 1;

    return *this;
}
*/

// ** inlined **

/*
Vec4& Vec4::MakeUnit() {

    real l = sqrt(_data[0]*_data[0] + _data[1]*_data[1] + _data[2]*_data[2]);
    if (l)
	for (int i=0; i<3; i++)
	    _data[i] /= l;
    else
        for (int i=0; i<3; i++)
            _data[i] = 0;

    return *this;
}
*/

void Vec4::MakeSqrtTable() {

	for (int i=0; i<SQRT_TABLE_SIZE+2; i++)
		Vec4::_sqrt_table[i] = sqrt((real) i / (real) SQRT_TABLE_SIZE);
}

/*
void Vec4::FastMakeUnit() {

	real approx_l = fabs(_data[0]) + fabs(_data[1]) + fabs(_data[2]);
	int subnormalize = (approx_l > 1);

	real w = ((_data[0] * _data[0]) +
			 (_data[1] * _data[1]) +
			 (_data[2] * _data[2])) * SQRT_TABLE_SIZE;
	if (subnormalize)
		w /= (approx_l * approx_l);

	int i = (int) w;
	w = w-i;
	real l = (Vec4::_sqrt_table[i+1] * w) + (Vec4::_sqrt_table[i] * (1-w));

	if (subnormalize)
		l *= approx_l;

	if (l) {
		_data[0] /= l;
		_data[1] /= l;
		_data[2] /= l;
	}
	else _data[0] = _data[1] = _data[2] = 0;
}
*/

Vec4 Vec4::Cross3(const Vec4 &v) {

    Vec4 c;

    c.Set(_data[1] * v._data[2] - _data[2] * v._data[1],
	- _data[0] * v._data[2] + _data[2] * v._data[0],
	  _data[0] * v._data[1] - _data[1] * v._data[0]);

    return c;
}

