/*
 * Copyright (c) 1992,1993-1995 Argonaut Technologies Limited. All rights reserved.
 *
 * $Id: vector.c 1.1 1997/12/10 16:41:23 jon Exp $
 * $Locker: $
 *
 * Vector op. - some of these are redefined as macros in vecfns.h
 * for speed. (but the real functions still exist for debugging purposes)
 *
 */

#undef _NO_VECTOR_MACROS
#define _NO_VECTOR_MACROS 1

#include "brender.h"
#include "shortcut.h"
#include "brassert.h"

BR_RCS_ID("$Id: vector.c 1.1 1997/12/10 16:41:23 jon Exp $")

/**
 ** 2D Vectors
 **/
void BR_PUBLIC_ENTRY BrVector2Copy(br_vector2 *v1,br_vector2 * v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

        v1->v[0]=v2->v[0];
	v1->v[1]=v2->v[1];
}

/*
 * v1=(s1,s2)
 */
void BR_PUBLIC_ENTRY BrVector2Set(br_vector2 *v1, br_scalar s1, br_scalar s2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);

	v1->v[0]=s1;
	v1->v[1]=s2;
}

void BR_PUBLIC_ENTRY BrVector2SetInt(br_vector2 *v1, int i1, int i2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);

	v1->v[0]=BrIntToScalar(i1);
	v1->v[1]=BrIntToScalar(i2);
}

void BR_PUBLIC_ENTRY BrVector2SetFloat(br_vector2 *v1, float f1, float f2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);

	v1->v[0]=BrFloatToScalar(f1);
	v1->v[1]=BrFloatToScalar(f2);
}

/*
 * v1=-v2
 */
void BR_PUBLIC_ENTRY BrVector2Negate(br_vector2 *v1, br_vector2 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=-v2->v[0];
	v1->v[1]=-v2->v[1];
}


/*
 * v1=v2+v3
 */
void BR_PUBLIC_ENTRY BrVector2Add(br_vector2 *v1, br_vector2 *v2, br_vector2 *v3)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Left Hand Source Vector is NULL", v2 != NULL);
        UASSERT_MESSAGE("Right Hand Source Vector is NULL", v3 != NULL);

	v1->v[0]=v2->v[0]+v3->v[0];
	v1->v[1]=v2->v[1]+v3->v[1];
}

/*
 * v1+=v2
 */
void BR_PUBLIC_ENTRY BrVector2Accumulate(br_vector2 *v1, br_vector2 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]+=v2->v[0];
	v1->v[1]+=v2->v[1];
}

/*
 * v1=v2-v3
 */
void BR_PUBLIC_ENTRY BrVector2Sub(br_vector2 *v1, br_vector2 *v2, br_vector2 *v3)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Left Hand Source Vector is NULL", v2 != NULL);
        UASSERT_MESSAGE("Right Hand Source Vector is NULL", v3 != NULL);

	v1->v[0]=v2->v[0]-v3->v[0];
	v1->v[1]=v2->v[1]-v3->v[1];
}

/*
 * v1=v2*scalar
 */
void BR_PUBLIC_ENTRY BrVector2Scale(br_vector2 *v1, br_vector2 *v2, br_scalar s)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);
        
	v1->v[0]=BR_MUL(v2->v[0],(s));
	v1->v[1]=BR_MUL(v2->v[1],(s));
}

/*
 * v1=v2/scalar
 */
void BR_PUBLIC_ENTRY BrVector2InvScale(br_vector2 *v1, br_vector2 *v2, br_scalar s)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=BR_DIV(v2->v[0],(s));
	v1->v[1]=BR_DIV(v2->v[1],(s));
}

/*
 *  = v1.v2
 */
br_scalar BR_PUBLIC_ENTRY BrVector2Dot(br_vector2 *v1, br_vector2 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	return BR_MAC2(v1->v[0],v2->v[0],v1->v[1],v2->v[1]);
}



/*
 *  = |v1|
 */
br_scalar BR_PUBLIC_ENTRY BrVector2Length(br_vector2 *v1)
{
        UASSERT_MESSAGE("Subject Vector is NULL", v1 != NULL);

	return BR_LENGTH2(v1->v[0],v1->v[1]);
}

/*
 *  = |v1| * |v1|
 */
br_scalar BR_PUBLIC_ENTRY BrVector2LengthSquared(br_vector2 *v1)
{
        UASSERT_MESSAGE("Subject Vector is NULL", v1 != NULL);

	return BR_SQR2(v1->v[0],v1->v[1]);
}

/**
 ** 3D VECTORS
 **/

/*
 * v1=v2
 */
void BR_PUBLIC_ENTRY BrVector3Copy(br_vector3 *v1, br_vector3 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=v2->v[0];
	v1->v[1]=v2->v[1];
	v1->v[2]=v2->v[2];
}


/*
 * v1=(s1,s2,s3)
 */
void BR_PUBLIC_ENTRY BrVector3Set(br_vector3 *v1, br_scalar s1, br_scalar s2, br_scalar s3)
{
        UASSERT_MESSAGE("Subject Vector is NULL", v1 != NULL);

	v1->v[0]=s1;
	v1->v[1]=s2;
	v1->v[2]=s3;
}

void BR_PUBLIC_ENTRY BrVector3SetInt(br_vector3 *v1, int i1, int i2, int i3)
{
        UASSERT_MESSAGE("Subject Vector is NULL", v1 != NULL);

	v1->v[0]=BrIntToScalar(i1);
	v1->v[1]=BrIntToScalar(i2);
	v1->v[2]=BrIntToScalar(i3);
}

void BR_PUBLIC_ENTRY BrVector3SetFloat(br_vector3 *v1, float f1, float f2, float f3)
{
        UASSERT_MESSAGE("Subject Vector is NULL", v1 != NULL);

	v1->v[0]=BrFloatToScalar(f1);
	v1->v[1]=BrFloatToScalar(f2);
	v1->v[2]=BrFloatToScalar(f3);
}

/*
 * v1=-v2
 */
void BR_PUBLIC_ENTRY BrVector3Negate(br_vector3 *v1,br_vector3 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v1 != NULL);

	v1->v[0]=-v2->v[0];
	v1->v[1]=-v2->v[1];
	v1->v[2]=-v2->v[2];
}


/*
 * v1=v2+v3
 */
void BR_PUBLIC_ENTRY BrVector3Add(br_vector3 *v1, br_vector3 *v2, br_vector3 *v3)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Left hand Source Vector is NULL", v2 != NULL);
        UASSERT_MESSAGE("Right Hand Source Vector is NULL", v3 != NULL);

	v1->v[0]=v2->v[0]+v3->v[0];
	v1->v[1]=v2->v[1]+v3->v[1];
	v1->v[2]=v2->v[2]+v3->v[2];
}

/*
 * v1+=v2
 */
void BR_PUBLIC_ENTRY BrVector3Accumulate(br_vector3 *v1, br_vector3 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]+=v2->v[0];
	v1->v[1]+=v2->v[1];
	v1->v[2]+=v2->v[2];
}

/*
 * v1=v2-v3
 */
void BR_PUBLIC_ENTRY BrVector3Sub(br_vector3 *v1, br_vector3 *v2, br_vector3 *v3)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Left hand Source Vector is NULL", v2 != NULL);
        UASSERT_MESSAGE("Right hand Source Vector is NULL", v3 != NULL);

	v1->v[0]=v2->v[0]-v3->v[0];
	v1->v[1]=v2->v[1]-v3->v[1];
	v1->v[2]=v2->v[2]-v3->v[2];
}

/*
 * v1=v2*scalar
 */
void BR_PUBLIC_ENTRY BrVector3Scale(br_vector3 *v1, br_vector3 *v2, br_scalar s)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=BR_MUL(v2->v[0],(s));
	v1->v[1]=BR_MUL(v2->v[1],(s));
	v1->v[2]=BR_MUL(v2->v[2],(s));
}

/*
 * v1=v2/scalar
 */
void BR_PUBLIC_ENTRY BrVector3InvScale(br_vector3 *v1, br_vector3 *v2, br_scalar s)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=BR_DIV(v2->v[0],(s));
	v1->v[1]=BR_DIV(v2->v[1],(s));
	v1->v[2]=BR_DIV(v2->v[2],(s));
}

/*
 *  = v1.v2
 */
br_scalar BR_PUBLIC_ENTRY BrVector3Dot(br_vector3 *v1, br_vector3 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	return BR_MAC3(v1->v[0],v2->v[0],v1->v[1],v2->v[1],v1->v[2],v2->v[2]);
}

/*
 * v1 = v2 x v3
 */
void BR_PUBLIC_ENTRY BrVector3Cross(br_vector3 *v1,br_vector3 *v2,br_vector3 *v3)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Left hand Source Vector is NULL", v2 != NULL);
        UASSERT_MESSAGE("Right hand Source Vector is NULL", v3 != NULL);
        UASSERT_MESSAGE("Destination vector may not be source", v1 != v2);
        UASSERT_MESSAGE("Destination vector may not be source", v1 != v3);
        
	v1->v[0]=BR_MUL(v2->v[1],v3->v[2])-BR_MUL(v2->v[2],v3->v[1]);
	v1->v[1]=BR_MUL(v2->v[2],v3->v[0])-BR_MUL(v2->v[0],v3->v[2]);
	v1->v[2]=BR_MUL(v2->v[0],v3->v[1])-BR_MUL(v2->v[1],v3->v[0]);
}

/*
 *  = |v1|
 */
br_scalar BR_PUBLIC_ENTRY BrVector3Length(br_vector3 *v1)
{
        UASSERT_MESSAGE("Subject Vector is NULL", v1 != NULL);

	return BR_LENGTH3(v1->v[0],v1->v[1],v1->v[2]);
}

/*
 * = |v1| * |v1|
 */
br_scalar BR_PUBLIC_ENTRY BrVector3LengthSquared(br_vector3 *v1)
{
        UASSERT_MESSAGE("Subject Vector is NULL", v1 != NULL);
        
        return BR_SQR3(v1->v[0],v1->v[1],v1->v[2]);
}

/*
 * v1 = v2/|v2|
 */
void BR_PUBLIC_ENTRY BrVector3Normalise(br_vector3 *v1, br_vector3 *v2)
{
	br_scalar scale;

        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);
        
	scale = BR_LENGTH3(v2->v[0],v2->v[1],v2->v[2]);

	if(scale > BR_SCALAR_EPSILON*2) {

		scale=BR_DIV(BR_SCALAR(1.0),scale);

		v1->v[0]=BR_MUL(v2->v[0],scale);
		v1->v[1]=BR_MUL(v2->v[1],scale);
		v1->v[2]=BR_MUL(v2->v[2],scale);

	} else {
		v1->v[0] = BR_SCALAR(1.0);
		v1->v[1] = BR_SCALAR(0.0);
		v1->v[2] = BR_SCALAR(0.0);
	}
}


/*
 * v1 = v2/|v2| (low precision)
 */
void BR_PUBLIC_ENTRY BrVector3NormaliseLP(br_vector3 *v1, br_vector3 *v2)
{
	br_scalar scale;

        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);
        
	scale = BR_RLENGTH3(v2->v[0],v2->v[1],v2->v[2]);

	if(scale != BR_SCALAR(0.0)) {
		v1->v[0]=BR_MUL(v2->v[0],scale);
		v1->v[1]=BR_MUL(v2->v[1],scale);
		v1->v[2]=BR_MUL(v2->v[2],scale);
	}
}



/**
 ** 4D Vectors
 **/
/*
 *  = v1.v2
 */
br_scalar BR_PUBLIC_ENTRY BrVector4Dot(br_vector4 *v1, br_vector4 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	return BR_MAC4(
		v1->v[0],v2->v[0],
		v1->v[1],v2->v[1],
		v1->v[2],v2->v[2],
		v1->v[3],v2->v[3]);
}

/*
 * v1=v2
 */
void BR_PUBLIC_ENTRY BrVector4Copy(br_vector4 *v1, br_vector4 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=v2->v[0];
	v1->v[1]=v2->v[1];
	v1->v[2]=v2->v[2];
	v1->v[3]=v2->v[3];
}

/**
 ** Private ops for fractional vectors
 **/

/*
 *  = v1.v2 (v1 is a unit vector (word components))
 */
br_scalar BrFVector2Dot(br_fvector2 *v1, br_vector2 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	return BR_FMAC2(v1->v[0],v2->v[0],v1->v[1],v2->v[1]);
}

/*
 * v1=v2
 */
void BrFVector3Copy(br_fvector3 *v1, br_vector3 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=BrScalarToFraction(v2->v[0]);
	v1->v[1]=BrScalarToFraction(v2->v[1]);
	v1->v[2]=BrScalarToFraction(v2->v[2]);
}

/*
 * v1=v2*scalar
 */
void BrVector3ScaleF(br_vector3 *v1, br_fvector3 *v2, br_scalar s)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=BR_MUL(BrFractionToScalar(v2->v[0]),s);
	v1->v[1]=BR_MUL(BrFractionToScalar(v2->v[1]),s);
	v1->v[2]=BR_MUL(BrFractionToScalar(v2->v[2]),s);
}


/*
 *  = v1.v2 (v1 is a unit vector (word components))
 */
br_scalar BrFVector3Dot(br_fvector3 *v1, br_vector3 *v2)
{
        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	return BR_FMAC3(v1->v[0],v2->v[0],v1->v[1],v2->v[1],v1->v[2],v2->v[2]);
}

/*
 * v1 = v2/|v2|
 */
void BrFVector3Normalise(br_fvector3 *v1,br_vector3 *v2)
{
	br_scalar scale;

        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	scale=BR_LENGTH3(v2->v[0],v2->v[1],v2->v[2]);

	if(scale != BR_SCALAR(0.0)) {

	scale=BR_DIV(BR_FRACTION(1.0),scale);

	v1->v[0]=(br_fraction)BR_MUL(v2->v[0],scale);
	v1->v[1]=(br_fraction)BR_MUL(v2->v[1],scale);
	v1->v[2]=(br_fraction)BR_MUL(v2->v[2],scale);

	} else {
		v1->v[0] = BR_FRACTION(1.0);
		v1->v[1] = BR_FRACTION(0.0);
		v1->v[2] = BR_FRACTION(0.0);
	}
}

/*
 * v1 = v2/|v2| (low precision)
 */
void BrFVector3NormaliseLP(br_fvector3 *v1, br_vector3 *v2)
{
	br_scalar scale = BrScalarToFraction(BR_RLENGTH3(v1->v[0],v1->v[1],v1->v[2]));

        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	v1->v[0]=(br_fraction)BR_MUL(v2->v[0],scale);
	v1->v[1]=(br_fraction)BR_MUL(v2->v[1],scale);
	v1->v[2]=(br_fraction)BR_MUL(v2->v[2],scale);
}

/*
 * v1 = v2/|v2|
 */
void BR_PUBLIC_ENTRY BrVector2Normalise(br_vector2 *v1, br_vector2 *v2)
{
	br_scalar scale;

	scale = BR_LENGTH2(v2->v[0],v2->v[1]);

        UASSERT_MESSAGE("Destination Vector is NULL", v1 != NULL);
        UASSERT_MESSAGE("Source Vector is NULL", v2 != NULL);

	if(scale > BR_SCALAR_EPSILON*2) {

		scale=BR_DIV(BR_SCALAR(1.0),scale);

		v1->v[0]=BR_MUL(v2->v[0],scale);
		v1->v[1]=BR_MUL(v2->v[1],scale);

	} else {
		v1->v[0] = BR_SCALAR(1.0);
		v1->v[1] = BR_SCALAR(0.0);
	}
}

