/*************************************************************************
 *                                                                       *
 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith.       *
 * All rights reserved.  Email: russ@q12.org   Web: www.q12.org          *
 *                                                                       *
 * This library is free software; you can redistribute it and/or         *
 * modify it under the terms of EITHER:                                  *
 *   (1) The GNU Lesser General Public License as published by the Free  *
 *       Software Foundation; either version 2.1 of the License, or (at  *
 *       your option) any later version. The text of the GNU Lesser      *
 *       General Public License is included with this library in the     *
 *       file LICENSE.TXT.                                               *
 *   (2) The BSD-style license that is included with this library in     *
 *       the file LICENSE-BSD.TXT.                                       *
 *                                                                       *
 * This library is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files    *
 * LICENSE.TXT and LICENSE-BSD.TXT for more details.                     *
 *                                                                       *
 *************************************************************************/

#ifndef _ODE_ODEMATH_H_
#define _ODE_ODEMATH_H_

#include <ode/common.h>

#ifdef __GNUC__
#define PURE_INLINE extern inline
#else
#define PURE_INLINE inline
#endif

/*
 * macro to access elements i,j in an NxM matrix A, independent of the
 * matrix storage convention.
 */
#define dACCESS33(A,i,j) ((A)[(i)*4+(j)])

/*
 * Macro to test for valid floating point values
 */
#define dVALIDVEC3(v) (!(dIsNan(v[0]) || dIsNan(v[1]) || dIsNan(v[2])))
#define dVALIDVEC4(v) (!(dIsNan(v[0]) || dIsNan(v[1]) || dIsNan(v[2]) || dIsNan(v[3])))
#define dVALIDMAT3(m) (!(dIsNan(m[0]) || dIsNan(m[1]) || dIsNan(m[2]) || dIsNan(m[3]) || dIsNan(m[4]) || dIsNan(m[5]) || dIsNan(m[6]) || dIsNan(m[7]) || dIsNan(m[8]) || dIsNan(m[9]) || dIsNan(m[10]) || dIsNan(m[11])))
#define dVALIDMAT4(m) (!(dIsNan(m[0]) || dIsNan(m[1]) || dIsNan(m[2]) || dIsNan(m[3]) || dIsNan(m[4]) || dIsNan(m[5]) || dIsNan(m[6]) || dIsNan(m[7]) || dIsNan(m[8]) || dIsNan(m[9]) || dIsNan(m[10]) || dIsNan(m[11]) || dIsNan(m[12]) || dIsNan(m[13]) || dIsNan(m[14]) || dIsNan(m[15]) ))



/*
 * General purpose vector operations with other vectors or constants.
 */

#define dOP(a,op,b,c) \
    (a)[0] = ((b)[0]) op ((c)[0]); \
    (a)[1] = ((b)[1]) op ((c)[1]); \
    (a)[2] = ((b)[2]) op ((c)[2]);
#define dOPC(a,op,b,c) \
    (a)[0] = ((b)[0]) op (c); \
    (a)[1] = ((b)[1]) op (c); \
    (a)[2] = ((b)[2]) op (c);
#define dOPE(a,op,b) \
    (a)[0] op ((b)[0]); \
    (a)[1] op ((b)[1]); \
    (a)[2] op ((b)[2]);
#define dOPEC(a,op,c) \
    (a)[0] op (c); \
    (a)[1] op (c); \
    (a)[2] op (c);

/// Define an equation with operatos
/// For example this function can be used to replace
/// <PRE>
/// for (int i=0; i<3; ++i)
///   a[i] += b[i] + c[i];
/// </PRE>
#define dOPE2(a,op1,b,op2,c) \
    (a)[0] op1 ((b)[0]) op2 ((c)[0]); \
    (a)[1] op1 ((b)[1]) op2 ((c)[1]); \
    (a)[2] op1 ((b)[2]) op2 ((c)[2]);

/*
 * Length, and squared length helpers. dLENGTH returns the length of a dVector3.
 * dLENGTHSQUARED return the squared length of a dVector3.
 */

#define dLENGTHSQUARED(a) (((a)[0])*((a)[0]) + ((a)[1])*((a)[1]) + ((a)[2])*((a)[2]))

#ifdef __cplusplus

PURE_INLINE dReal dLENGTH (const dReal *a) { return dSqrt(dLENGTHSQUARED(a)); }

#else

#define dLENGTH(a) ( dSqrt( ((a)[0])*((a)[0]) + ((a)[1])*((a)[1]) + ((a)[2])*((a)[2]) ) )

#endif /* __cplusplus */





/*
 * 3-way dot product. dDOTpq means that elements of `a' and `b' are spaced
 * p and q indexes apart respectively. dDOT() means dDOT11.
 * in C++ we could use function templates to get all the versions of these
 * functions - but on some compilers this will result in sub-optimal code.
 */

#define dDOTpq(a,b,p,q) ((a)[0]*(b)[0] + (a)[p]*(b)[q] + (a)[2*(p)]*(b)[2*(q)])

#ifdef PSPOPTS_ODEMATH

PURE_INLINE dReal dMagnitude_ (const dReal *a) {
	if (isnan(*a)) return 0;
	dReal result;
	   __asm__ volatile (
	       "ulv.q    R000, %1\n"
	       "vdot.t  S000, R000, R000\n"
	       "vsqrt.s S000, S000\n"
	       "mfv      %0, S000\n"   
	       : "=r"(result): "m"(*a):"$f0");
	return result;
}
PURE_INLINE dReal dSquareMagnitude_ (const dReal *a) {
	dReal ret;
	    __asm__ volatile (
	       "ulv.q    R000, %1\n"
	       "vdot.t   S000, R000, R000\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a):"$f0");
	return ret;
}
PURE_INLINE dReal dDOT_ (const dReal *a, const dReal *b) {
	dReal ret;
	    __asm__ volatile (
	       "ulv.q    R000, %1\n"
	       "ulv.q    R001, %2\n"
	       "vdot.t   S000, R000, R001\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a), "m"(*b):"$f0","$f1");
	return ret;
}
PURE_INLINE dReal dDOT13_ (const dReal *a, const dReal *b) {
	dReal ret;
	    __asm__ volatile (
	       "ulv.q    R000, %1\n"
	       "ulv.s     S001, 0+  %2\n"
	       "ulv.s     S011, 12+ %2\n"
	       "ulv.s     S021, 24+ %2\n"
	       "vdot.t   S000, R000, R001\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a), "m"(*b):"$f0");
	return ret;
}
PURE_INLINE dReal dDOT31_ (const dReal *a, const dReal *b) {
	dReal ret;
	    __asm__ volatile (
	       "ulv.q    R000, %2\n"
	       "lv.s     S001, 0+  %1\n"
	       "lv.s     S011, 12+ %1\n"
	       "lv.s     S021, 24+ %1\n"
	       "vdot.t   S000, R000, R001\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a), "m"(*b):"$f0");
	return ret;
}
PURE_INLINE dReal dDOT33_ (const dReal *a, const dReal *b) {
	dReal ret;
	    __asm__ volatile (
	       "lv.s     S000, 0+  %1\n"
	       "lv.s     S010, 12+ %1\n"
	       "lv.s     S020, 24+ %1\n"
	       "lv.s     S001, 0+  %2\n"
	       "lv.s     S011, 12+ %2\n"
	       "lv.s     S021, 24+ %2\n"
	       "vdot.t   S000, R000, R001\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a), "m"(*b));
	return ret;
}
PURE_INLINE dReal dDOT14_ (const dReal *a, const dReal *b) {
	dReal ret;
	    __asm__ volatile (
	       "ulv.q    R000, %1\n"
	       "lv.s     S001, 0+  %2\n"
	       "lv.s     S011, 16+ %2\n"
	       "lv.s     S021, 32+ %2\n"
	       "vdot.t   S000, R000, R001\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a), "m"(*b):"$f0");
	return ret;
}
PURE_INLINE dReal dDOT41_ (const dReal *a, const dReal *b) {
	dReal ret;
	    __asm__ volatile (
	       "ulv.q    R000, %2\n"
	       "lv.s     S001, 0+  %1\n"
	       "lv.s     S011, 16+ %1\n"
	       "lv.s     S021, 32+ %1\n"
	       "vdot.t   S000, R000, R001\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a), "m"(*b):"$f0");
	return ret;
}
PURE_INLINE dReal dDOT44_ (const dReal *a, const dReal *b) {
	dReal ret;
	    __asm__ volatile (
	       "lv.s     S000, 0+  %1\n"
	       "lv.s     S010, 16+ %1\n"
	       "lv.s     S020, 32+ %1\n"
	       "lv.s     S001, 0+  %2\n"
	       "lv.s     S011, 16+ %2\n"
	       "lv.s     S021, 32+ %2\n"
	       "vdot.t   S000, R000, R001\n"
	       "mfv      %0, S000\n"   
	       : "=r"(ret): "m"(*a), "m"(*b));
	return ret;
}
#else
#define dDOT_(a,b)   dDOTpq(a,b,1,1)
PURE_INLINE dReal dMagnitude_ (const dReal *a) { return dSqrt(dDOT_(a,a)); }
#define dDOT13_(a,b)   dDOT13(a,b)
#define dDOT31_(a,b)   dDOT31(a,b)
#define dDOT33_(a,b)   dDOT33(a,b)
#define dDOT41_(a,b)   dDOT41(a,b)
#define dDOT14_(a,b)   dDOT14(a,b)
#define dDOT44_(a,b)   dDOT44(a,b)
#define dSquareMagnitude_(a)    dDOTpq(a,a,1,1)

#endif /* PSP */


#ifdef __cplusplus
PURE_INLINE dReal dDOT   (const dReal *a, const dReal *b) { return dDOTpq(a,b,1,1); }
PURE_INLINE dReal dDOT13 (const dReal *a, const dReal *b) { return dDOTpq(a,b,1,3); }
PURE_INLINE dReal dDOT31 (const dReal *a, const dReal *b) { return dDOTpq(a,b,3,1); }
PURE_INLINE dReal dDOT33 (const dReal *a, const dReal *b) { return dDOTpq(a,b,3,3); }
PURE_INLINE dReal dDOT14 (const dReal *a, const dReal *b) { return dDOTpq(a,b,1,4); }
PURE_INLINE dReal dDOT41 (const dReal *a, const dReal *b) { return dDOTpq(a,b,4,1); }
PURE_INLINE dReal dDOT44 (const dReal *a, const dReal *b) { return dDOTpq(a,b,4,4); }
#else
#define dDOT(a,b)   dDOTpq(a,b,1,1)
#define dDOT13(a,b) dDOTpq(a,b,1,3)
#define dDOT31(a,b) dDOTpq(a,b,3,1)
#define dDOT33(a,b) dDOTpq(a,b,3,3)
#define dDOT14(a,b) dDOTpq(a,b,1,4)
#define dDOT41(a,b) dDOTpq(a,b,4,1)
#define dDOT44(a,b) dDOTpq(a,b,4,4)
#endif /* __cplusplus */

/*
 * cross product, set a = b x c. dCROSSpqr means that elements of `a', `b'
 * and `c' are spaced p, q and r indexes apart respectively.
 * dCROSS() means dCROSS111. `op' is normally `=', but you can set it to
 * +=, -= etc to get other effects.
 */

#ifndef PSPOPTS_ODEMATH
	#define dCROSS_EQ(a,b,c) dCROSS (a,=,b,c)
	#define dCROSS_PLUSEQ(a,b,c) dCROSS (a,+=,b,c)
#else 
	PURE_INLINE void dCROSS_EQ (dReal *  a, dReal *  b, dReal *  c) {
		    __asm__ volatile (
		       "ulv.q    R000, %1\n"
		       "ulv.q    R001, %2\n"
		       "vcrsp.t	R002, R000, R001\n"		// cross product
		       "usv.q    R002, %0\n"
		       : "=m"(*a): "m"(*b), "m"(*c):"$f0","$f1");
	}
	PURE_INLINE void dCROSS_PLUSEQ (dReal * a, dReal *  b, dReal *  c) {
		    __asm__ volatile (
		       "ulv.q    R000, %1\n"
		       "ulv.q    R001, %2\n"
		       "ulv.q    R003, %0\n"
		       "vcrsp.t	 R002, R000, R001\n"
		       "vadd.t   R003, R002, R003\n"
		       "usv.q    R003, %0\n"
		       : "+m"(*a): "m"(*b), "m"(*c):"$f0","$f1","$f3");
	}
#endif

#define dCROSS(a,op,b,c) \
  (a)[0] op ((b)[1]*(c)[2] - (b)[2]*(c)[1]); \
  (a)[1] op ((b)[2]*(c)[0] - (b)[0]*(c)[2]); \
  (a)[2] op ((b)[0]*(c)[1] - (b)[1]*(c)[0]);

#define dCROSSpqr(a,op,b,c,p,q,r) \
do { \
  (a)[  0] op ((b)[  q]*(c)[2*r] - (b)[2*q]*(c)[  r]); \
  (a)[  p] op ((b)[2*q]*(c)[  0] - (b)[  0]*(c)[2*r]); \
  (a)[2*p] op ((b)[  0]*(c)[  r] - (b)[  q]*(c)[  0]); \
} while(0)
#define dCROSS114(a,op,b,c) dCROSSpqr(a,op,b,c,1,1,4)
#define dCROSS141(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,1)
#define dCROSS144(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,4)
#define dCROSS411(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,1)
#define dCROSS414(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,4)
#define dCROSS441(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,1)
#define dCROSS444(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,4)


/*
 * set a 3x3 submatrix of A to a matrix such that submatrix(A)*b = a x b.
 * A is stored by rows, and has `skip' elements per row. the matrix is
 * assumed to be already zero, so this does not write zero elements!
 * if (plus,minus) is (+,-) then a positive version will be written.
 * if (plus,minus) is (-,+) then a negative version will be written.
 */

#define dCROSSMAT(A,a,skip,plus,minus) \
do { \
  (A)[1] = minus (a)[2]; \
  (A)[2] = plus (a)[1]; \
  (A)[(skip)+0] = plus (a)[2]; \
  (A)[(skip)+2] = minus (a)[0]; \
  (A)[2*(skip)+0] = minus (a)[1]; \
  (A)[2*(skip)+1] = plus (a)[0]; \
} while(0)


/*
 * compute the distance between two 3D-vectors
 */

#ifdef __cplusplus
PURE_INLINE dReal dDISTANCE (const dVector3 a, const dVector3 b)
	{ return dSqrt( (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]) ); }
#else
#define dDISTANCE(a,b) \
	(dSqrt( ((a)[0]-(b)[0])*((a)[0]-(b)[0]) + ((a)[1]-(b)[1])*((a)[1]-(b)[1]) + ((a)[2]-(b)[2])*((a)[2]-(b)[2]) ))
#endif


/*
 * special case matrix multipication, with operator selection
 */

#define dMULTIPLYOP0_331(A,op,B,C) \
do { \
  (A)[0] op dDOT((B),(C)); \
  (A)[1] op dDOT((B+4),(C)); \
  (A)[2] op dDOT((B+8),(C)); \
} while(0)
#define dMULTIPLYOP1_331(A,op,B,C) \
do { \
  (A)[0] op dDOT41((B),(C)); \
  (A)[1] op dDOT41((B+1),(C)); \
  (A)[2] op dDOT41((B+2),(C)); \
} while(0)
#define dMULTIPLYOP0_133(A,op,B,C) \
do { \
  (A)[0] op dDOT14((B),(C)); \
  (A)[1] op dDOT14((B),(C+1)); \
  (A)[2] op dDOT14((B),(C+2)); \
} while(0)
#define dMULTIPLYOP0_333(A,op,B,C) \
do { \
  (A)[0] op dDOT14((B),(C)); \
  (A)[1] op dDOT14((B),(C+1)); \
  (A)[2] op dDOT14((B),(C+2)); \
  (A)[4] op dDOT14((B+4),(C)); \
  (A)[5] op dDOT14((B+4),(C+1)); \
  (A)[6] op dDOT14((B+4),(C+2)); \
  (A)[8] op dDOT14((B+8),(C)); \
  (A)[9] op dDOT14((B+8),(C+1)); \
  (A)[10] op dDOT14((B+8),(C+2)); \
} while(0)
#define dMULTIPLYOP1_333(A,op,B,C) \
do { \
  (A)[0] op dDOT44((B),(C)); \
  (A)[1] op dDOT44((B),(C+1)); \
  (A)[2] op dDOT44((B),(C+2)); \
  (A)[4] op dDOT44((B+1),(C)); \
  (A)[5] op dDOT44((B+1),(C+1)); \
  (A)[6] op dDOT44((B+1),(C+2)); \
  (A)[8] op dDOT44((B+2),(C)); \
  (A)[9] op dDOT44((B+2),(C+1)); \
  (A)[10] op dDOT44((B+2),(C+2)); \
} while(0)
#define dMULTIPLYOP2_333(A,op,B,C) \
do { \
  (A)[0] op dDOT((B),(C)); \
  (A)[1] op dDOT((B),(C+4)); \
  (A)[2] op dDOT((B),(C+8)); \
  (A)[4] op dDOT((B+4),(C)); \
  (A)[5] op dDOT((B+4),(C+4)); \
  (A)[6] op dDOT((B+4),(C+8)); \
  (A)[8] op dDOT((B+8),(C)); \
  (A)[9] op dDOT((B+8),(C+4)); \
  (A)[10] op dDOT((B+8),(C+8)); \
} while(0)


#ifdef __cplusplus
#define DECL template <class TA, class TB, class TC> PURE_INLINE void
DECL dMULTIPLY0_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_331(A,=,B,C); }
DECL dMULTIPLY1_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_331(A,=,B,C); }
DECL dMULTIPLY0_133(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_133(A,=,B,C); }
DECL dMULTIPLY0_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_333(A,=,B,C); }
DECL dMULTIPLY1_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_333(A,=,B,C); }
DECL dMULTIPLY2_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP2_333(A,=,B,C); }

DECL dMULTIPLYADD0_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_331(A,+=,B,C); }
DECL dMULTIPLYADD1_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_331(A,+=,B,C); }
DECL dMULTIPLYADD0_133(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_133(A,+=,B,C); }
DECL dMULTIPLYADD0_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_333(A,+=,B,C); }
DECL dMULTIPLYADD1_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_333(A,+=,B,C); }
DECL dMULTIPLYADD2_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP2_333(A,+=,B,C); }

#undef DECL

#else

#define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C)
#define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C)
#define dMULTIPLY0_133(A,B,C) dMULTIPLYOP0_133(A,=,B,C)
#define dMULTIPLY0_333(A,B,C) dMULTIPLYOP0_333(A,=,B,C)
#define dMULTIPLY1_333(A,B,C) dMULTIPLYOP1_333(A,=,B,C)
#define dMULTIPLY2_333(A,B,C) dMULTIPLYOP2_333(A,=,B,C)

#define dMULTIPLYADD0_331(A,B,C) dMULTIPLYOP0_331(A,+=,B,C)
#define dMULTIPLYADD1_331(A,B,C) dMULTIPLYOP1_331(A,+=,B,C)
#define dMULTIPLYADD0_133(A,B,C) dMULTIPLYOP0_133(A,+=,B,C)
#define dMULTIPLYADD0_333(A,B,C) dMULTIPLYOP0_333(A,+=,B,C)
#define dMULTIPLYADD1_333(A,B,C) dMULTIPLYOP1_333(A,+=,B,C)
#define dMULTIPLYADD2_333(A,B,C) dMULTIPLYOP2_333(A,+=,B,C)

#endif


#ifdef PSPOPTS_ODEMATH__
	PURE_INLINE void dMULTIPLY0_331_ (dReal* vout, const dReal* mat, const dReal* v) {
	    __asm__ volatile (
	       "ulv.q    R000, 0+  %1\n"
	       "ulv.q    R001, 16+ %1\n"
	       "ulv.q    R002, 32+ %1\n"
	       "ulv.q    R300, %2\n"

	       "vtfm3.t  R101, E000, R300\n"

	       "usv.q    R101, %0\n"
	       : "+m"(vout[0]): "m"(mat[0]), "m"(v[0]):"$f0","$f1","$f2","$f12");
	}
	PURE_INLINE void dMULTIPLYADD0_331_ (dReal* vout, const dReal* mat, const dReal* v) {
	    __asm__ volatile (
	       "ulv.q    R000, 0+  %1\n"
	       "ulv.q    R001, 16+ %1\n"
	       "ulv.q    R002, 32+ %1\n"
	       "ulv.q    R300, %2\n"
	       "ulv.q    R320, %0\n"

	       "vtfm3.t  R101, E000, R300\n"
	       "vadd.t   R101, R320, R101\n"

	       "usv.q    R101, %0\n"
	       : "+m"(vout[0]): "m"(mat[0]), "m"(v[0]):"$f0","$f1","$f2","$f12","$f14");
	}
	// Some aligned data versions to speed up some functions
	PURE_INLINE void dMULTIPLYADD0_331_ALIGNED (dReal* vout, const dReal* mat, const dReal* v) {
	    __asm__ volatile (
	       "lv.q    R000, 0+  %1\n"
	       "lv.q    R001, 16+ %1\n"
	       "lv.q    R002, 32+ %1\n"
	       "lv.q    C100, %2\n"
	       "lv.q    C120, %0\n"

	       "vtfm3.t  C110, E000, C100\n"
	       "vadd.t   C110, C120, C110\n"

	       "sv.q    C110, %0\n"
	       : "+m"(vout[0]): "m"(mat[0]), "m"(v[0]):"$f0","$f1","$f2","$f4","$f6");
	}
	PURE_INLINE void dMULTIPLY1_331_ (dReal* vout, const dReal* mat, const dReal* v) {
	    __asm__ volatile (
	       "ulv.q    R000, 0+  %1\n"
	       "ulv.q    R001, 16+ %1\n"
	       "ulv.q    R002, 32+ %1\n"
	       "ulv.q    R300, %2\n"

	       "vtfm3.t  R003, M000, R300\n"

	       "usv.q    R003, %0\n"
	       : "+m"(vout[0]): "m"(mat[0]), "m"(v[0]):"$f0","$f1","$f2","$f12");
	}
	PURE_INLINE void dMULTIPLY0_133_ (dReal* vout, const dReal* v,const dReal* mat) {
	    __asm__ volatile (
	       "ulv.q    R000, 0+  %1\n"
	       "ulv.q    R001, 16+ %1\n"
	       "ulv.q    R002, 32+ %1\n"
	       "ulv.q    R300, %2\n"

	       "vtfm3.t  R101, E000, R300\n"

	       "usv.q    R101, %0\n"
	       : "+m"(vout[0]): "m"(mat[0]), "m"(v[0]):"$f0","$f1","$f2","$f12");
	}
	PURE_INLINE void dMULTIPLY0_333_ (dReal* mout, const dReal* m1, const dReal* m2) {
		    __asm__ volatile (
		       "ulv.q    R000, 0+  %1\n"
		       "ulv.q    R001, 16+ %1\n"
		       "ulv.q    R002, 32+ %1\n"
		       "ulv.q    R300, 0+  %2\n"
		       "ulv.q    R301, 16+ %2\n"
		       "ulv.q    R302, 32+ %2\n"
		       "vmmul.t  M200, M000, M300\n"
		       "usv.q    R200, 0+  %0\n"
		       "usv.q    R201, 16+ %0\n"
		       "usv.q    R202, 32+ %0\n"
		       : "+m"(mout[0]): "m"(m1[0]), "m"(m2[0]):"$f0","$f1","$f2","$f12","$f13","$f14");
	}
	PURE_INLINE void dMULTIPLY1_333_ (dReal* mout, const dReal* m1, const dReal* m2) {
		    __asm__ volatile (
		       "ulv.q    R000, 0+  %1\n"
		       "ulv.q    R001, 16+ %1\n"
		       "ulv.q    R002, 32+ %1\n"
		       "ulv.q    R300, 0+  %2\n"
		       "ulv.q    R301, 16+ %2\n"
		       "ulv.q    R302, 32+ %2\n"
		       "vmmul.t  M200, E000, M300\n"
		       "usv.q    R200, 0+  %0\n"
		       "usv.q    R201, 16+ %0\n"
		       "usv.q    R202, 32+ %0\n"
		       : "+m"(mout[0]): "m"(m1[0]), "m"(m2[0]):"$f0","$f1","$f2","$f12","$f13","$f14");
	}
	PURE_INLINE void dMULTIPLY2_333_ (dReal* mout, const dReal* m1, const dReal* m2) {
		    __asm__ volatile (
		       "ulv.q    R000, 0+  %1\n"
		       "ulv.q    R001, 16+ %1\n"
		       "ulv.q    R002, 32+ %1\n"
		       "ulv.q    R300, 0+  %2\n"
		       "ulv.q    R301, 16+ %2\n"
		       "ulv.q    R302, 32+ %2\n"
		       "vmmul.t  M200, M000, E300\n"
		       "usv.q    R200, 0+  %0\n"
		       "usv.q    R201, 16+ %0\n"
		       "usv.q    R202, 32+ %0\n"
		       : "+m"(mout[0]): "m"(m1[0]), "m"(m2[0]):"$f0","$f1","$f2","$f12","$f13","$f14");
	}
#else
	#define dMULTIPLY0_331_(a,b,c)   dMULTIPLY0_331(a,b,c)
	#define dMULTIPLY1_331_(a,b,c)   dMULTIPLY1_331(a,b,c)
	#define dMULTIPLY0_133_(a,b,c)   dMULTIPLY0_133(a,b,c)
	#define dMULTIPLY0_333_(a,b,c)   dMULTIPLY0_333(a,b,c)
	#define dMULTIPLY1_333_(a,b,c)   dMULTIPLY1_333(a,b,c)
	#define dMULTIPLY2_333_(a,b,c)   dMULTIPLY2_333(a,b,c)
	#define dMULTIPLYADD0_331_(A,B,C) dMULTIPLYADD0_331(A,B,C)

	#define dMULTIPLYADD0_331_ALIGNED(A,B,C) dMULTIPLYADD0_331(A,B,C)
#endif 


#ifdef __cplusplus
extern "C" {
#endif

/*
 * normalize 3x1 and 4x1 vectors (i.e. scale them to unit length)
 */

#if defined(__ODE__)

int  _dSafeNormalize3 (dVector3 a);
int  _dSafeNormalize4 (dVector4 a);
	
static __inline void _dNormalize3(dVector3 a)
{
	int bNormalizationResult = _dSafeNormalize3(a);
	dIASSERT(bNormalizationResult);
	dVARIABLEUSED(bNormalizationResult);
}

static __inline void _dNormalize4(dVector4 a)
{
	int bNormalizationResult = _dSafeNormalize4(a);
	dIASSERT(bNormalizationResult);
	dVARIABLEUSED(bNormalizationResult);
}

#endif // defined(__ODE__)

// For DLL export
ODE_API int  dSafeNormalize3 (dVector3 a);
ODE_API int  dSafeNormalize4 (dVector4 a);
ODE_API void dNormalize3 (dVector3 a); // Potentially asserts on zero vec
ODE_API void dNormalize4 (dVector4 a); // Potentially asserts on zero vec

#if defined(__ODE__)

// For internal use
#define dSafeNormalize3(a) _dSafeNormalize3(a)
#define dSafeNormalize4(a) _dSafeNormalize4(a)
#define dNormalize3(a) _dNormalize3(a)
#define dNormalize4(a) _dNormalize4(a)

#endif // defined(__ODE__)

/*
 * given a unit length "normal" vector n, generate vectors p and q vectors
 * that are an orthonormal basis for the plane space perpendicular to n.
 * i.e. this makes p,q such that n,p,q are all perpendicular to each other.
 * q will equal n x p. if n is not unit length then p will be unit length but
 * q wont be.
 */

ODE_API void dPlaneSpace (const dVector3 n, dVector3 p, dVector3 q);
/* Makes sure the matrix is a proper rotation */
ODE_API void dOrthogonalizeR(dMatrix3 m);



#ifdef __cplusplus
}
#endif

#endif
