Si vous trouvez que DirectXMath est un peu trop verbeux pour vos goûts, jetez un oeil à SimpleMath dans le DirectX Tool Kit. En particulier, la classe Vector2
:
struct Vector2 : public XMFLOAT2
{
Vector2() : XMFLOAT2(0.f, 0.f) {}
explicit Vector2(float x) : XMFLOAT2(x, x) {}
Vector2(float _x, float _y) : XMFLOAT2(_x, _y) {}
explicit Vector2(_In_reads_(2) const float *pArray) : XMFLOAT2(pArray) {}
Vector2(FXMVECTOR V) { XMStoreFloat2(this, V); }
Vector2(const XMFLOAT2& V) { this->x = V.x; this->y = V.y; }
explicit Vector2(const XMVECTORF32& F) { this->x = F.f[0]; this->y = F.f[1]; }
operator XMVECTOR() const { return XMLoadFloat2(this); }
// Comparison operators
bool operator == (const Vector2& V) const;
bool operator != (const Vector2& V) const;
// Assignment operators
Vector2& operator= (const Vector2& V) { x = V.x; y = V.y; return *this; }
Vector2& operator= (const XMFLOAT2& V) { x = V.x; y = V.y; return *this; }
Vector2& operator= (const XMVECTORF32& F) { x = F.f[0]; y = F.f[1]; return *this; }
Vector2& operator+= (const Vector2& V);
Vector2& operator-= (const Vector2& V);
Vector2& operator*= (const Vector2& V);
Vector2& operator*= (float S);
Vector2& operator/= (float S);
// Unary operators
Vector2 operator+() const { return *this; }
Vector2 operator-() const { return Vector2(-x, -y); }
// Vector operations
bool InBounds(const Vector2& Bounds) const;
float Length() const;
float LengthSquared() const;
float Dot(const Vector2& V) const;
void Cross(const Vector2& V, Vector2& result) const;
Vector2 Cross(const Vector2& V) const;
void Normalize();
void Normalize(Vector2& result) const;
void Clamp(const Vector2& vmin, const Vector2& vmax);
void Clamp(const Vector2& vmin, const Vector2& vmax, Vector2& result) const;
// Static functions
static float Distance(const Vector2& v1, const Vector2& v2);
static float DistanceSquared(const Vector2& v1, const Vector2& v2);
static void Min(const Vector2& v1, const Vector2& v2, Vector2& result);
static Vector2 Min(const Vector2& v1, const Vector2& v2);
static void Max(const Vector2& v1, const Vector2& v2, Vector2& result);
static Vector2 Max(const Vector2& v1, const Vector2& v2);
static void Lerp(const Vector2& v1, const Vector2& v2, float t, Vector2& result);
static Vector2 Lerp(const Vector2& v1, const Vector2& v2, float t);
static void SmoothStep(const Vector2& v1, const Vector2& v2, float t, Vector2& result);
static Vector2 SmoothStep(const Vector2& v1, const Vector2& v2, float t);
static void Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g, Vector2& result);
static Vector2 Barycentric(const Vector2& v1, const Vector2& v2, const Vector2& v3, float f, float g);
static void CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t, Vector2& result);
static Vector2 CatmullRom(const Vector2& v1, const Vector2& v2, const Vector2& v3, const Vector2& v4, float t);
static void Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t, Vector2& result);
static Vector2 Hermite(const Vector2& v1, const Vector2& t1, const Vector2& v2, const Vector2& t2, float t);
static void Reflect(const Vector2& ivec, const Vector2& nvec, Vector2& result);
static Vector2 Reflect(const Vector2& ivec, const Vector2& nvec);
static void Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex, Vector2& result);
static Vector2 Refract(const Vector2& ivec, const Vector2& nvec, float refractionIndex);
static void Transform(const Vector2& v, const Quaternion& quat, Vector2& result);
static Vector2 Transform(const Vector2& v, const Quaternion& quat);
static void Transform(const Vector2& v, const Matrix& m, Vector2& result);
static Vector2 Transform(const Vector2& v, const Matrix& m);
static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray);
static void Transform(const Vector2& v, const Matrix& m, Vector4& result);
static void Transform(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector4* resultArray);
static void TransformNormal(const Vector2& v, const Matrix& m, Vector2& result);
static Vector2 TransformNormal(const Vector2& v, const Matrix& m);
static void TransformNormal(_In_reads_(count) const Vector2* varray, size_t count, const Matrix& m, _Out_writes_(count) Vector2* resultArray);
// Constants
static const Vector2 Zero;
static const Vector2 One;
static const Vector2 UnitX;
static const Vector2 UnitY;
};
// Binary operators
Vector2 operator+ (const Vector2& V1, const Vector2& V2);
Vector2 operator- (const Vector2& V1, const Vector2& V2);
Vector2 operator* (const Vector2& V1, const Vector2& V2);
Vector2 operator* (const Vector2& V, float S);
Vector2 operator/ (const Vector2& V1, const Vector2& V2);
Vector2 operator* (float S, const Vector2& V);
La principale raison pour laquelle DirectXMath est si bavard en premier lieu est de le rendre très clair pour le programmeur lorsque « renverser la mémoire », car cela a tendance à avoir un impact négatif sur les performances des Code SIMD. Quand je suis passé de XNAMath à DirectXMath, j'avais envisagé d'ajouter quelque chose comme les conversions implicites que j'ai utilisées pour "SimpleMath", mais je voulais m'assurer que de telles "magies C++" étaient opt-in et jamais une surprise pour une performance sensible. développeur. SimpleMath agit également un peu comme des roues d'entraînement, ce qui facilite le portage du code existant qui ne tient pas compte de l'alignement et le transforme en quelque chose de plus SIMD-friendly au fil du temps. Le vrai problème de performance avec SimpleMath (et votre wrapper) est que chaque implémentation de la fonction doit faire un chargement explicite & Stocker autour de ce qui est par ailleurs une quantité relativement faible de SIMD. Idéalement, dans un code optimisé, tout serait fusionné, mais dans le code de débogage, ils sont toujours là. Pour tout gain de performance réel de SIMD, vous voulez avoir de longues séries d'opérations SIMD dans le registre entre chaque paire de magasins Load &.
Une autre implication est que le paramètre passant un wrapper comme Vector2
ou votre Vector2F
ne sera jamais particulièrement efficace. La raison pour laquelle XMVECTOR
est un typedef pour __m128
plutôt qu'une struct, et l'existence de FXMVECTOR
, GXMVECTOR
, HXMVECTOR
, et CXMVECTOR
est d'essayer d'optimiser tous les scénarios de convention d'appel possibles et dans le meilleur des cas obtenir un comportement de passage en registre (si les choses ne s'introduisent pas).Voir MSDN. Vraiment le meilleur que vous pouvez faire avec Vector2
est de toujours le passer const&
pour minimiser les temporaires et empiler des copies.
Je pense que vous trouverez que dans le code optimisé, la pénalité de performance sera nulle. –
Si la valeur renvoyée n'est pas utilisée, le compilateur optimisera très probablement 'return * this;'. C'est un idiome commun que les compilateurs connaissent bien. –
Vous avez deux conversions implicites: 1) à partir de XMVECTOR et 2) à XMVECTOR. C'est une grande possibilité d'ambiguïté. Ne faites pas ça (n'utilisez pas Vector2F). –