/* =========================================================================== maya2q3 - export .md3 files from maya Copyright (C) 2007 HermitWorks Entertainment Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. =========================================================================== */ #ifndef INC__vector_h_ #define INC__vector_h_ /* Constructors are kept as seperate functions as putting them in their type will force constructors to propagate up through any class/struct that includes a vecN. Even if the default constructor is empty and gets optimized away this causes some stupid issues when trying to stick a vector in a union or at global scope. Three cheers for the C++ spec which doesn't treat an empty default constructor the same as the implied default constructor when there are no other constructors. And for those that haven't noticed the convention is struct vecN, with create functions vecNv that takes a pointer to N floats and vecNc that takes a combination of floats and other vectors. The usual addition and subtraction operators are defined for all vector types, as are the usual multiplication and division operators. There are also componentwise multiplication and division operators that take vectors (of the same dimension). */ struct vec2 { public: float x, y; inline operator const float* ( void ) const { return &x; } inline operator float* ( void ) { return &x; } inline vec2 operator + ( const vec2 &v ) const { vec2 ret = { x + v.x, y + v.y }; return ret; } inline vec2& operator += ( const vec2 &v ) { x += v.x; y += v.y; return *this; } inline vec2 operator - ( void ) const { vec2 ret = { -x, -y }; return ret; } inline vec2 operator - ( const vec2 &v ) const { vec2 ret = { x - v.x, y - v.y }; return ret; } inline vec2& operator -= ( const vec2 &v ) { x -= v.x; y -= v.y; return *this; } inline vec2 operator * ( float s ) const { vec2 ret = { x * s, y * s }; return ret; } inline vec2& operator *= ( float s ) { x *= s; y *= s; return *this; } inline vec2 operator * ( const vec2 &v ) const { vec2 ret = { x * v.x, y * v.y }; return ret; } inline vec2& operator *= ( const vec2 &v ) { x *= v.x; y *= v.y; return *this; } inline vec2 operator / ( float s ) const { s = 1.0F / s; vec2 ret = { x * s, y * s }; return ret; } inline vec2& operator /= ( float s ) { s = 1.0F / s; x *= s; y *= s; return *this; } inline vec2 operator / ( const vec2 &v ) const { vec2 ret = { x / v.x, y / v.y }; return ret; } inline vec2& operator /= ( const vec2 &v ) { x /= v.x; y /= v.y; return *this; } static const vec2 zero; }; inline vec2 vec2v( const float *v ) { vec2 ret = { v[0], v[1] }; return ret; } inline vec2 vec2c( float xy ) { vec2 ret = { xy, xy }; return ret; } inline vec2 vec2c( float x, float y ) { vec2 ret = { x, y }; return ret; } inline float dot( const vec2 &l, const vec2 &r ) { return l.x * r.x + l.y * r.y; } inline float hadd( const vec2 &v ) { return v.x + v.y; } inline vec2 rcp( const vec2 &v ) { return vec2c( 1.0F / v.x, 1.0F / v.y ); } inline vec2 min( const vec2 &v0, const vec2 &v1 ) { return vec2c( min( v0.x, v1.x ), min( v0.y, v1.y ) ); } inline vec2 max( const vec2 &v0, const vec2 &v1 ) { return vec2c( max( v0.x, v1.x ), max( v0.y, v1.y ) ); } inline vec2 abs( const vec2 &v ) { return vec2c( abs( v.x ), abs( v.y ) ); } inline bool equal( const vec2 &v0, const vec2 &v1, float tol ) { return fabsf( v0.x - v1.x ) <= tol && fabsf( v0.y - v1.y ) <= tol; } struct vec3 { public: float x, y, z; inline operator const float* ( void ) const { return &x; } inline operator float* ( void ) { return &x; } inline vec3 operator + ( const vec3 &v ) const { vec3 ret = { x + v.x, y + v.y, z + v.z }; return ret; } inline vec3& operator += ( const vec3 &v ) { x += v.x; y += v.y; z += v.z; return *this; } inline vec3 operator - ( void ) const { vec3 ret = { -x, -y, -z }; return ret; } inline vec3 operator - ( const vec3 &v ) const { vec3 ret = { x - v.x, y - v.y, z - v.z }; return ret; } inline vec3& operator -= ( const vec3 &v ) { x -= v.x; y -= v.y; z -= v.z; return *this; } inline vec3 operator * ( float s ) const { vec3 ret = { x * s, y * s, z * s }; return ret; } inline vec3& operator *= ( float s ) { x *= s; y *= s; z *= s; return *this; } inline vec3 operator * ( const vec3 &v ) const { vec3 ret = { x * v.x, y * v.y, z * v.z }; return ret; } inline vec3& operator *= ( const vec3 &v ) { x *= v.x; y *= v.y; z *= v.z; return *this; } inline vec3 operator / ( float s ) const { s = 1.0F / s; vec3 ret = { x * s, y * s, z * s }; return ret; } inline vec3& operator /= ( float s ) { s = 1.0F / s; x *= s; y *= s; z *= s; return *this; } inline vec3 operator / ( const vec3 &v ) const { vec3 ret = { x / v.x, y / v.y, z / v.z }; return ret; } inline vec3& operator /= ( const vec3 &v ) { x /= v.x; y /= v.y; z /= v.z; return *this; } static const vec3 zero; }; inline vec3 vec3v( const float *v ) { vec3 ret = { v[0], v[1], v[2] }; return ret; } inline vec3 vec3c( float xyz ) { vec3 ret = { xyz, xyz, xyz }; return ret; } inline vec3 vec3c( float x, float y, float z ) { vec3 ret = { x, y, z }; return ret; } inline vec3 vec3c( const vec2 &xy, float z ) { vec3 ret = { xy.x, xy.y, z }; return ret; } inline float dot( const vec3 &l, const vec3 &r ) { return l.x * r.x + l.y * r.y + l.z * r.z; } inline vec3 cross( const vec3 &l, const vec3 &r ) { return vec3c( l.y * r.z - l.z * r.y, l.z * r.x - l.x * r.z, l.x * r.y - l.y * r.x ); } inline float hadd( const vec3 &v ) { return v.x + v.y + v.z; } inline vec3 rcp( const vec3 &v ) { return vec3c( 1.0F / v.x, 1.0F / v.y, 1.0F / v.z ); } inline float lengthsq( const vec3 &v ) { return dot( v, v ); } inline float length( const vec3 &v ) { return sqrt( lengthsq( v ) ); } inline vec3 lerp( const vec3 &v0, const vec3 &v1, float t ) { return v0 * (1.0F - t) + v1 * t; } inline float dist( const vec3 &p0, const vec3 &p1 ) { return length( p1 - p0 ); } inline vec3 normalize( const vec3 &v ) { return v / length( v ); } inline vec3 min( const vec3 &v0, const vec3 &v1 ) { return vec3c( min( v0.x, v1.x ), min( v0.y, v1.y ), min( v0.z, v1.z ) ); } inline vec3 max( const vec3 &v0, const vec3 &v1 ) { return vec3c( max( v0.x, v1.x ), max( v0.y, v1.y ), min( v0.z, v1.z ) ); } inline vec3 abs( const vec3 &v ) { return vec3c( abs( v.x ), abs( v.y ), abs( v.z ) ); } inline vec3 ceil( const vec3 &v ) { return vec3c( ceil( v.x ), ceil( v.y ), ceil( v.z ) ); } inline vec3 floor( const vec3 &v ) { return vec3c( floor( v.x ), floor( v.y ), floor( v.z ) ); } inline bool equal( const vec3 &v0, const vec3 &v1, float tol ) { return fabsf( v0.x - v1.x ) <= tol && fabsf( v0.y - v1.y ) <= tol && fabsf( v0.z - v1.z ) <= tol; } __declspec( align( 16 ) ) struct vec4 { public: float x, y, z, w; //ugly! aweful! but ooh so useful! inline const vec3& xyz( void ) const { return *reinterpret_cast< const vec3* >( this ); } inline vec3& xyz( void ) { return *reinterpret_cast< vec3* >( this ); } inline operator const float* ( void ) const { return &x; } inline operator float* ( void ) { return &x; } inline vec4 operator + ( const vec4 &v ) const { vec4 ret = { x + v.x, y + v.y, z + v.z, w + v.w }; return ret; } inline vec4& operator += ( const vec4 &v ) { x += v.x; y += v.y; z += v.z; w += v.w; return *this; } inline vec4 operator - ( void ) const { vec4 ret = { -x, -y, -z, -w }; return ret; } inline vec4 operator - ( const vec4 &v ) const { vec4 ret = { x - v.x, y - v.y, z - v.z, w - v.w }; return ret; } inline vec4& operator -= ( const vec4 &v ) { x -= v.x; y -= v.y; z -= v.z; w -= v.w; return *this; } inline vec4 operator * ( float s ) const { vec4 ret = { x * s, y * s, z * s, w * s }; return ret; } inline vec4& operator *= ( float s ) { x *= s; y *= s; z *= s; w *= s; return *this; } inline vec4 operator * ( const vec4 &v ) const { vec4 ret = { x * v.x, y * v.y, z * v.z, w * v.w }; return ret; } inline vec4& operator *= ( const vec4 &v ) { x *= v.x; y *= v.y; z *= v.z; w *= v.w; return *this; } inline vec4 operator / ( float s ) const { s = 1.0F / s; vec4 ret = { x * s, y * s, z * s, w * s }; return ret; } inline vec4& operator /= ( float s ) { s = 1.0F / s; x *= s; y *= s; z *= s; w *= s; return *this; } inline vec4 operator / ( const vec4 &v ) const { vec4 ret = { x / v.x, y / v.y, z / v.z, w / v.w }; return ret; } inline vec4& operator /= ( const vec4 &v ) { x /= v.x; y /= v.y; z /= v.z; w /= v.w; return *this; } static const vec4 zero; }; inline vec4 vec4v( const float *v ) { vec4 ret = { v[0], v[1], v[2], v[3] }; return ret; } inline vec4 vec4c( float xyzw ) { vec4 ret = { xyzw, xyzw, xyzw, xyzw }; return ret; } inline vec4 vec4c( float x, float y, float z, float w ) { vec4 ret = { x, y, z, w }; return ret; } inline vec4 vec4c( const vec2 &xy, const vec2 &zw ) { vec4 ret = { xy.x, xy.y, zw.x, zw.y }; return ret; } inline vec4 vec4c( const vec3 &xyz, float w ) { vec4 ret = { xyz.x, xyz.y, xyz.z, w }; return ret; } inline float dot( const vec4 &l, const vec4 &r ) { return l.x * r.x + l.y * r.y + l.z * r.z + l.w * r.w; } inline float doth( const vec4 &l, const vec3 &r ) { return l.x * r.x + l.y * r.y + l.z * r.z + l.w; } inline float hadd( const vec4 &v ) { return v.x + v.y + v.z + v.w; } inline vec3 persp_div( const vec4 &v ) { return v.xyz() / v.w; } /****************************************************************************** Vector packing goodness. ******************************************************************************/ //the sb format packs by subtracting b and multiplying by s template< unsigned int n, unsigned int s, unsigned int b = 0 > struct vec_s16sb { short v[n]; vec_s16sb( void ) { } vec_s16sb( const float src[n] ) { for( unsigned int i = 0; i < n; i++ ) v[i] = Pack( src[i] ); } vec_s16sb( const vec_s16sb &src ) { for( unsigned int i = 0; i < n; i++ ) v[i] = src.v[i]; } inline vec_s16sb& operator = ( const float src[n] ) { for( unsigned int i = 0; i < n; i++ ) v[i] = Pack( src[i] ); return *this; } inline vec_s16sb& operator = ( const vec_s16sb &src ) { for( unsigned int i = 0; i < n; i++ ) v[i] = src.v[i]; return *this; } inline void Unpack( float *v ) const { for( unsigned int i = 0; i < n; i++ ) v[i] = Unpack( v[i] ); } inline operator short* ( void ) { return v; } inline operator const short* ( void ) const { return v; } private: inline short Pack( float v ) { return (short)((v - (float)b) * (float)s); } inline float Unpack( short v ) { return (float)v / (float)s + (float)b; } }; //the eb format packs the range (b - e, b + e) into a short template< unsigned int n, unsigned int e = 1, unsigned int b = 0 > struct vec_s16eb { short v[n]; vec_s16eb( void ) { } vec_s16eb( const float src[n] ) { for( unsigned int i = 0; i < n; i++ ) v[i] = Pack( src[i] ); } vec_s16eb( const vec_s16eb &src ) { for( unsigned int i = 0; i < n; i++ ) v[i] = src.v[i]; } inline vec_s16eb& operator = ( const float src[n] ) { for( unsigned int i = 0; i < n; i++ ) v[i] = Pack( src[i] ); return *this; } inline vec_s16eb& operator = ( const vec_s16eb &src ) { for( unsigned int i = 0; i < n; i++ ) v[i] = src.v[i]; return *this; } inline void Unpack( float *v ) const { for( unsigned int i = 0; i < n; i++ ) v[i] = Unpack( v[i] ); } inline operator short* ( void ) { return v; } inline operator const short* ( void ) const { return v; } private: inline short Pack( float v ) { if( v < (int)b - (int)e ) v = (int)b - (int)e; if( v > (int)b + (int)e ) v = (int)b + (int)e; return (short)((v - (int)b) * (32767.0F / e)); } inline float Unpack( short v ) { return v * (e / 32767.0F) + b; } }; #endif