C
kleine änderung, jetzt funktioniert shuffle auch mit gcc. irgendwie funktioniert es dort nur, wenn ich auf v direkt zugreife, obwohl ja ein cast operator da ist; ich denke das ist ein compilerfehler, bei funktionen, die keine template funktionen sind, geht es ja schliesslich. leider krieg ich die syntax, um jede instanz des funktions-templates friend zu machen, nicht auf die reihe, also sind die daten jetzt public.
hier mal eine einigermassen funktionsfähige 3dklasse
#ifndef VECTOR3D_H_INCLUDED
#define VECTOR3D_H_INCLUDED
#include <cstdlib>
#include <cassert>
#include "SSEIntrin.h"
class Vector3d
{
public:
SSE::Xmm4f v;
Vector3d() { }
Vector3d(const SSE::Xmm4f& r): v( r ) { }
Vector3d(float x, float y, float z): v( x, y, z, 1.0f ) { }
float& operator[](std::size_t i) { assert( i < 3 ); return v[ i ]; }
const float& operator[](std::size_t i)const { assert( i < 3 ); return v[ i ]; }
Vector3d operator +()const { return v; }
Vector3d operator -()const { return -v; }
Vector3d& operator*=(float k) { v *= k; return *this; }
Vector3d& operator/=(float k) { v /= k; return *this; }
float length()const
{
SSE::Xmm4f tmp1( v * v );
SSE::Xmm4f tmp2;
tmp2 = SSE::shuffle< 2, 3, 2, 3 >( tmp1, tmp2 ); // resolves to movehl
// [2] and [3] of tmp2 are actually undefined, which is why the default constructor
// doesnt initialize anything, since it couldnt be optimized away
tmp2 = addss( tmp2, tmp1 ); // now holds v[0]+v[2]
tmp1 = SSE::shuffle< 1, 0, 0, 0 >( tmp1 );
tmp2 = addss( tmp2, tmp1 );
tmp2 = sqrtss( tmp2 );
return tmp2;
}
float sqrLength()const
{
SSE::Xmm4f tmp1( v * v );
SSE::Xmm4f tmp2;
tmp2 = SSE::shuffle< 2, 3, 2, 3 >( tmp1, tmp2 );
tmp2 = addss( tmp2, tmp1 );
tmp1 = SSE::shuffle< 1, 0, 0, 0 >( tmp1 );
tmp2 = addss( tmp2, tmp1 );
return tmp2;
}
Vector3d& normalize()
{
SSE::Xmm4f tmp1( v * v );
SSE::Xmm4f tmp2;
tmp2 = SSE::shuffle< 2, 3, 2, 3>( tmp1, tmp2 );
tmp2 = addss( tmp2, tmp1 );
tmp1 = SSE::shuffle< 1, 0, 0, 0>( tmp1 );
tmp2 = addss( tmp2, tmp1 );
tmp2 = rsqrtss( tmp2 );
tmp2 = SSE::shuffle< 0, 0, 0, 1>( tmp2 );
v *= tmp2;
return *this;
}
};
inline Vector3d operator+(const Vector3d& l, const Vector3d& r) { return l.v + r.v; }
inline Vector3d operator-(const Vector3d& l, const Vector3d& r) { return l.v - r.v; }
inline float operator*(const Vector3d& l, const Vector3d& r)
{
SSE::Xmm4f tmp1( l.v * r.v );
SSE::Xmm4f tmp2;
tmp2 = SSE::shuffle< 2, 3, 2, 3 >( tmp1, tmp2 );
tmp2 = addss( tmp2, tmp1 );
tmp1 = SSE::shuffle< 1, 0, 0, 0 >( tmp1 );
tmp2 = addss( tmp2, tmp1 );
return tmp2;
}
inline Vector3d vectorp(const Vector3d& l, const Vector3d& r)
{
SSE::Xmm4f tmp1( SSE::shuffle< 2, 0, 1, 3 >( l.v ) );
SSE::Xmm4f tmp2( SSE::shuffle< 1, 2, 0, 3 >( r.v ) );
SSE::Xmm4f tmp3( tmp1 * tmp2 );
tmp1 = SSE::shuffle< 2, 0, 1, 3 >( tmp1 );
tmp2 = SSE::shuffle< 1, 2, 0, 1 >( tmp2 );
tmp1 *= tmp2;
tmp1 -= tmp3;
return tmp1;
}
inline bool operator==(const Vector3d& l, const Vector3d& r)
{
return !( ( l.v != r.v ) & 7 ); // mask unused vector element
}
inline bool operator!=(const Vector3d& l, const Vector3d& r)
{
return ( l.v != r.v ) & 7;
}
#endif // #ifndef VECTOR3D_H_INCLUDED
auf die verwendung der 4. koordinate hab ich verzichtet, weil das zusätzlichen code erfordert. im zusammenhang mit matrixoperationen muss man dann davon ausgehen, dass diese koordinate 1 sein soll, unabhängig davon, was tatsächlich drin steht - das sollte auch dort code sparen.
*= rsqrt(.. ist übrigens deutlich schneller als /= sqrt(..
da rsqrt genauso schnell wie eine divison ist, allerdings ist es auch deutlich ungenauer (allerdings genauer als der workaround in dem anderen thread), man vergleiche einfach mal vec.normalize() mit vec /= vec.length().
im übrigen würde mich interessieren, ob das alles hier bei jemandem einen messbaren vorteil bringt