Neomi
2006-01-22, 20:15:18
Für eine komfortablere Programmierung habe ich mir Arbitrary Swizzling für Vektoren (2D, 3D und 4D, letztere aber nicht im Codeauszug enthalten) nachgebaut. Hier erstmal ein wenig Code aus der relevanten Header-Datei:
#ifndef _INC_VECTORS_H_
#define _INC_VECTORS_H_
// low level macros
#define Vector2_AssignOp(Op,Index0,Index1) \
Vector2 operator Op (Vector2 Src) \
{ \
m [Index0] Op Src.x; \
m [Index1] Op Src.y; \
\
return (Vector2 (m [Index0], m [Index1])); \
}
#define Vector3_AssignOp(Op,Index0,Index1,Index2) \
Vector3 operator Op (Vector3 Src) \
{ \
m [Index0] Op Src.x; \
m [Index1] Op Src.y; \
m [Index2] Op Src.z; \
\
return (Vector3 (m [Index0], m [Index1], m [Index2])); \
}
#define Vector2_AssignOps(Op,Index0,Index1) \
Vector2_AssignOp (Op, Index0, Index1); \
Vector2 operator Op (float Src) { return (operator Op (Vector2 (Src, Src))); }
#define Vector3_AssignOps(Op,Index0,Index1,Index2) \
Vector3_AssignOp (Op, Index0, Index1, Index2); \
Vector3 operator Op (float Src) { return (operator Op (Vector3 (Src, Src, Src))); } \
Vector3 operator Op (Vector2 Src) { return (operator Op (Vector3 (Src.x, Src.y, Src.y))); }
#define Vector2_CastOp(Index0,Index1) \
operator Vector2 () const \
{ \
return (Vector2 (m [Index0], m [Index1])); \
}
#define Vector3_CastOp(Index0,Index1,Index2) \
operator Vector3 () const \
{ \
return (Vector3 (m [Index0], m [Index1], m [Index2])); \
}
// read only masks
#define Vector2_Comp2_RO(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [2]; \
\
public: \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp2_RO(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp3_RO(Name,Index0,Index1,Index2) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector3_CastOp (Index0, Index1, Index2); \
} Name
// read and write masks
#define Vector2_Comp2_RW(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [2]; \
\
public: \
Vector2_AssignOps ( =, Index0, Index1); \
Vector2_AssignOps (+=, Index0, Index1); \
Vector2_AssignOps (-=, Index0, Index1); \
Vector2_AssignOps (*=, Index0, Index1); \
Vector2_AssignOps (/=, Index0, Index1); \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp2_RW(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector2_AssignOps ( =, Index0, Index1); \
Vector2_AssignOps (+=, Index0, Index1); \
Vector2_AssignOps (-=, Index0, Index1); \
Vector2_AssignOps (*=, Index0, Index1); \
Vector2_AssignOps (/=, Index0, Index1); \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp3_RW(Name,Index0,Index1,Index2) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector3_AssignOps ( =, Index0, Index1, Index2); \
Vector3_AssignOps (+=, Index0, Index1, Index2); \
Vector3_AssignOps (-=, Index0, Index1, Index2); \
Vector3_AssignOps (*=, Index0, Index1, Index2); \
Vector3_AssignOps (/=, Index0, Index1, Index2); \
Vector3_CastOp (Index0, Index1, Index2); \
} Name
// vector structures
union Vector2
{
struct
{
float x;
float y;
};
float m [2];
Vector2 () {}
Vector2 (float x, float y) : x (x), y (y) {}
Vector2_Comp2_RO (xx, 0, 0);
Vector2_Comp2_RW (xy, 0, 1);
Vector2_Comp2_RW (yx, 1, 0);
Vector2_Comp2_RO (yy, 1, 1);
};
union Vector3
{
struct
{
float x;
float y;
float z;
};
float m [3];
Vector3 () {}
Vector3 (float x, float y, float z) : x (x), y (y), z (z) {}
Vector3 (Vector2 v2xy, float z) : x (v2xy.x), y (v2xy.y), z (z) {}
Vector3 (float x, Vector2 v2yz) : x (x), y (v2yz.x), z (v2yz.y) {}
Vector3_Comp2_RO (xx, 0, 0);
Vector3_Comp2_RW (xy, 0, 1);
Vector3_Comp2_RW (xz, 0, 2);
Vector3_Comp2_RW (yx, 1, 0);
Vector3_Comp2_RO (yy, 1, 1);
Vector3_Comp2_RW (yz, 1, 2);
Vector3_Comp2_RW (zx, 2, 0);
Vector3_Comp2_RW (zy, 2, 1);
Vector3_Comp2_RO (zz, 2, 2);
Vector3_Comp3_RO (xxx, 0, 0, 0);
Vector3_Comp3_RO (xxy, 0, 0, 1);
Vector3_Comp3_RO (xxz, 0, 0, 2);
Vector3_Comp3_RO (xyx, 0, 1, 0);
Vector3_Comp3_RO (xyy, 0, 1, 1);
Vector3_Comp3_RW (xyz, 0, 1, 2);
Vector3_Comp3_RO (xzx, 0, 2, 0);
Vector3_Comp3_RW (xzy, 0, 2, 1);
Vector3_Comp3_RO (xzz, 0, 2, 2);
Vector3_Comp3_RO (yxx, 1, 0, 0);
Vector3_Comp3_RO (yxy, 1, 0, 1);
Vector3_Comp3_RW (yxz, 1, 0, 2);
Vector3_Comp3_RO (yyx, 1, 1, 0);
Vector3_Comp3_RO (yyy, 1, 1, 1);
Vector3_Comp3_RO (yyz, 1, 1, 2);
Vector3_Comp3_RW (yzx, 1, 2, 0);
Vector3_Comp3_RO (yzy, 1, 2, 1);
Vector3_Comp3_RO (yzz, 1, 2, 2);
Vector3_Comp3_RO (zxx, 2, 0, 0);
Vector3_Comp3_RW (zxy, 2, 0, 1);
Vector3_Comp3_RO (zxz, 2, 0, 2);
Vector3_Comp3_RW (zyx, 2, 1, 0);
Vector3_Comp3_RO (zyy, 2, 1, 1);
Vector3_Comp3_RO (zyz, 2, 1, 2);
Vector3_Comp3_RO (zzx, 2, 2, 0);
Vector3_Comp3_RO (zzy, 2, 2, 1);
Vector3_Comp3_RO (zzz, 2, 2, 2);
};
// undefine macros
#undef Vector2_AssignOp
#undef Vector3_AssignOp
#undef Vector2_AssignOps
#undef Vector3_AssignOps
#undef Vector2_CastOp
#undef Vector3_CastOp
#undef Vector2_Comp2_RO
#undef Vector3_Comp2_RO
#undef Vector3_Comp3_RO
#undef Vector2_Comp2_RW
#undef Vector3_Comp2_RW
#undef Vector3_Comp3_RW
// Vector2 operators
inline Vector2 operator + (Vector2 Src)
{
return (Src);
}
inline Vector2 operator - (Vector2 Src)
{
return (Vector2 (-Src.x, -Src.y));
}
inline Vector2 operator + (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x + Src2.x, Src1.y + Src2.y));
}
inline Vector2 operator - (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x - Src2.x, Src1.y - Src2.y));
}
inline Vector2 operator * (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x * Src2.x, Src1.y * Src2.y));
}
inline Vector2 operator / (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x / Src2.x, Src1.y / Src2.y));
}
inline Vector2 & operator += (Vector2 & Dst, Vector2 Src)
{
Dst.x += Src.x;
Dst.y += Src.y;
return (Dst);
}
inline Vector2 & operator -= (Vector2 & Dst, Vector2 Src)
{
Dst.x -= Src.x;
Dst.y -= Src.y;
return (Dst);
}
inline Vector2 & operator *= (Vector2 & Dst, Vector2 Src)
{
Dst.x *= Src.x;
Dst.y *= Src.y;
return (Dst);
}
inline Vector2 & operator /= (Vector2 & Dst, Vector2 Src)
{
Dst.x /= Src.x;
Dst.y /= Src.y;
return (Dst);
}
// Vector3 operators
inline Vector3 operator + (Vector3 Src)
{
return (Src);
}
inline Vector3 operator - (Vector3 Src)
{
return (Vector3 (-Src.x, -Src.y, -Src.z));
}
inline Vector3 operator + (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x + Src2.x, Src1.y + Src2.y, Src1.z + Src2.z));
}
inline Vector3 operator - (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x - Src2.x, Src1.y - Src2.y, Src1.z - Src2.z));
}
inline Vector3 operator * (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x * Src2.x, Src1.y * Src2.y, Src1.z * Src2.z));
}
inline Vector3 operator / (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x / Src2.x, Src1.y / Src2.y, Src1.z / Src2.z));
}
inline Vector3 & operator += (Vector3 & Dst, Vector3 Src)
{
Dst.x += Src.x;
Dst.y += Src.y;
Dst.z += Src.z;
return (Dst);
}
inline Vector3 & operator -= (Vector3 & Dst, Vector3 Src)
{
Dst.x -= Src.x;
Dst.y -= Src.y;
Dst.z -= Src.z;
return (Dst);
}
inline Vector3 & operator *= (Vector3 & Dst, Vector3 Src)
{
Dst.x *= Src.x;
Dst.y *= Src.y;
Dst.z *= Src.z;
return (Dst);
}
inline Vector3 & operator /= (Vector3 & Dst, Vector3 Src)
{
Dst.x /= Src.x;
Dst.y /= Src.y;
Dst.z /= Src.z;
return (Dst);
}
// additional operators for mixed types
inline Vector2 operator + (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) + Src2); }
inline Vector3 operator + (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) + Src2); }
inline Vector2 operator + (Vector2 Src1, float Src2) { return (Src1 + Vector2 (Src2, Src2)); }
inline Vector3 operator + (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) + Src2); }
inline Vector3 operator + (Vector3 Src1, float Src2) { return (Src1 + Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator + (Vector3 Src1, Vector2 Src2) { return (Src1 + Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 operator - (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) - Src2); }
inline Vector3 operator - (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) - Src2); }
inline Vector2 operator - (Vector2 Src1, float Src2) { return (Src1 - Vector2 (Src2, Src2)); }
inline Vector3 operator - (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) - Src2); }
inline Vector3 operator - (Vector3 Src1, float Src2) { return (Src1 - Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator - (Vector3 Src1, Vector2 Src2) { return (Src1 - Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 operator * (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) * Src2); }
inline Vector3 operator * (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) * Src2); }
inline Vector2 operator * (Vector2 Src1, float Src2) { return (Src1 * Vector2 (Src2, Src2)); }
inline Vector3 operator * (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) * Src2); }
inline Vector3 operator * (Vector3 Src1, float Src2) { return (Src1 * Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator * (Vector3 Src1, Vector2 Src2) { return (Src1 * Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 operator / (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) / Src2); }
inline Vector3 operator / (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) / Src2); }
inline Vector2 operator / (Vector2 Src1, float Src2) { return (Src1 / Vector2 (Src2, Src2)); }
inline Vector3 operator / (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) / Src2); }
inline Vector3 operator / (Vector3 Src1, float Src2) { return (Src1 / Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator / (Vector3 Src1, Vector2 Src2) { return (Src1 / Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 & operator += (Vector2 & Dst, float Src) { return (Dst += Vector2 (Src, Src)); }
inline Vector3 & operator += (Vector3 & Dst, float Src) { return (Dst += Vector3 (Src, Src, Src)); }
inline Vector3 & operator += (Vector3 & Dst, Vector2 Src) { return (Dst += Vector3 (Src.x, Src.y, Src.y)); }
inline Vector2 & operator -= (Vector2 & Dst, float Src) { return (Dst -= Vector2 (Src, Src)); }
inline Vector3 & operator -= (Vector3 & Dst, float Src) { return (Dst -= Vector3 (Src, Src, Src)); }
inline Vector3 & operator -= (Vector3 & Dst, Vector2 Src) { return (Dst -= Vector3 (Src.x, Src.y, Src.y)); }
inline Vector2 & operator *= (Vector2 & Dst, float Src) { return (Dst *= Vector2 (Src, Src)); }
inline Vector3 & operator *= (Vector3 & Dst, float Src) { return (Dst *= Vector3 (Src, Src, Src)); }
inline Vector3 & operator *= (Vector3 & Dst, Vector2 Src) { return (Dst *= Vector3 (Src.x, Src.y, Src.y)); }
inline Vector2 & operator /= (Vector2 & Dst, float Src) { return (Dst /= Vector2 (Src, Src)); }
inline Vector3 & operator /= (Vector3 & Dst, float Src) { return (Dst /= Vector3 (Src, Src, Src)); }
inline Vector3 & operator /= (Vector3 & Dst, Vector2 Src) { return (Dst /= Vector3 (Src.x, Src.y, Src.y)); }
#endif // _INC_VECTORS_H_
Mein Problem ist jetzt, daß der Compiler mit seinen Optimierungen (ich habe alles durchprobiert, was die Performance steigern kann) nicht soviel rausholt, wie machbar ist. Zum Testen habe ich das Kreuzprodukt in diesen beiden Varianten genommen:
inline Vector3 cross1 (Vector3 v1, Vector3 v2)
{
Vector3 v;
v.x = v1.y * v2.z - v1.z * v2.y;
v.y = v1.z * v2.x - v1.x * v2.z;
v.z = v1.x * v2.y - v1.y * v2.x;
return (v);
}
inline Vector3 cross2 (Vector3 v1, Vector3 v2)
{
return (v1.yzx * v2.zxy - v1.zxy * v2.yzx);
}
Wenn ich jetzt in einer Schleife (ich habe dafür gesorgt, daß das Ergebnis nicht verworfen wird) 100.000.000 mal das Kreuzprodukt berechne, spüre ich einen deutlichen Unterschied zwischen den beiden Varianten, cross2 ist um einiges langsamer. Und das, obwohl die beiden Varianten mathematisch äquivalent sind (bzw. sein sollten, die Rundungsfehler sind mit und ohne Float Consistency bei beiden Varianten etwas anders) und es im fertigen Code in dieser Schleife keinen einzigen Call mehr gibt.
Hat jemand eine Idee, was ich direkt im Code noch tun kann? Außer dem Verzicht auf das Swizzling natürlich. Ich möchte jederzeit das Swizzling nutzen können und trotzdem die maximale Performance haben.
PS: holt der Compiler von VS .Net 2005 vielleicht (deutlich) mehr raus? Dann würde ich wohl auf lange Sicht umsteigen.
#ifndef _INC_VECTORS_H_
#define _INC_VECTORS_H_
// low level macros
#define Vector2_AssignOp(Op,Index0,Index1) \
Vector2 operator Op (Vector2 Src) \
{ \
m [Index0] Op Src.x; \
m [Index1] Op Src.y; \
\
return (Vector2 (m [Index0], m [Index1])); \
}
#define Vector3_AssignOp(Op,Index0,Index1,Index2) \
Vector3 operator Op (Vector3 Src) \
{ \
m [Index0] Op Src.x; \
m [Index1] Op Src.y; \
m [Index2] Op Src.z; \
\
return (Vector3 (m [Index0], m [Index1], m [Index2])); \
}
#define Vector2_AssignOps(Op,Index0,Index1) \
Vector2_AssignOp (Op, Index0, Index1); \
Vector2 operator Op (float Src) { return (operator Op (Vector2 (Src, Src))); }
#define Vector3_AssignOps(Op,Index0,Index1,Index2) \
Vector3_AssignOp (Op, Index0, Index1, Index2); \
Vector3 operator Op (float Src) { return (operator Op (Vector3 (Src, Src, Src))); } \
Vector3 operator Op (Vector2 Src) { return (operator Op (Vector3 (Src.x, Src.y, Src.y))); }
#define Vector2_CastOp(Index0,Index1) \
operator Vector2 () const \
{ \
return (Vector2 (m [Index0], m [Index1])); \
}
#define Vector3_CastOp(Index0,Index1,Index2) \
operator Vector3 () const \
{ \
return (Vector3 (m [Index0], m [Index1], m [Index2])); \
}
// read only masks
#define Vector2_Comp2_RO(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [2]; \
\
public: \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp2_RO(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp3_RO(Name,Index0,Index1,Index2) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector3_CastOp (Index0, Index1, Index2); \
} Name
// read and write masks
#define Vector2_Comp2_RW(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [2]; \
\
public: \
Vector2_AssignOps ( =, Index0, Index1); \
Vector2_AssignOps (+=, Index0, Index1); \
Vector2_AssignOps (-=, Index0, Index1); \
Vector2_AssignOps (*=, Index0, Index1); \
Vector2_AssignOps (/=, Index0, Index1); \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp2_RW(Name,Index0,Index1) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector2_AssignOps ( =, Index0, Index1); \
Vector2_AssignOps (+=, Index0, Index1); \
Vector2_AssignOps (-=, Index0, Index1); \
Vector2_AssignOps (*=, Index0, Index1); \
Vector2_AssignOps (/=, Index0, Index1); \
Vector2_CastOp (Index0, Index1); \
} Name
#define Vector3_Comp3_RW(Name,Index0,Index1,Index2) \
struct _##Name \
{ \
private: \
float m [3]; \
\
public: \
Vector3_AssignOps ( =, Index0, Index1, Index2); \
Vector3_AssignOps (+=, Index0, Index1, Index2); \
Vector3_AssignOps (-=, Index0, Index1, Index2); \
Vector3_AssignOps (*=, Index0, Index1, Index2); \
Vector3_AssignOps (/=, Index0, Index1, Index2); \
Vector3_CastOp (Index0, Index1, Index2); \
} Name
// vector structures
union Vector2
{
struct
{
float x;
float y;
};
float m [2];
Vector2 () {}
Vector2 (float x, float y) : x (x), y (y) {}
Vector2_Comp2_RO (xx, 0, 0);
Vector2_Comp2_RW (xy, 0, 1);
Vector2_Comp2_RW (yx, 1, 0);
Vector2_Comp2_RO (yy, 1, 1);
};
union Vector3
{
struct
{
float x;
float y;
float z;
};
float m [3];
Vector3 () {}
Vector3 (float x, float y, float z) : x (x), y (y), z (z) {}
Vector3 (Vector2 v2xy, float z) : x (v2xy.x), y (v2xy.y), z (z) {}
Vector3 (float x, Vector2 v2yz) : x (x), y (v2yz.x), z (v2yz.y) {}
Vector3_Comp2_RO (xx, 0, 0);
Vector3_Comp2_RW (xy, 0, 1);
Vector3_Comp2_RW (xz, 0, 2);
Vector3_Comp2_RW (yx, 1, 0);
Vector3_Comp2_RO (yy, 1, 1);
Vector3_Comp2_RW (yz, 1, 2);
Vector3_Comp2_RW (zx, 2, 0);
Vector3_Comp2_RW (zy, 2, 1);
Vector3_Comp2_RO (zz, 2, 2);
Vector3_Comp3_RO (xxx, 0, 0, 0);
Vector3_Comp3_RO (xxy, 0, 0, 1);
Vector3_Comp3_RO (xxz, 0, 0, 2);
Vector3_Comp3_RO (xyx, 0, 1, 0);
Vector3_Comp3_RO (xyy, 0, 1, 1);
Vector3_Comp3_RW (xyz, 0, 1, 2);
Vector3_Comp3_RO (xzx, 0, 2, 0);
Vector3_Comp3_RW (xzy, 0, 2, 1);
Vector3_Comp3_RO (xzz, 0, 2, 2);
Vector3_Comp3_RO (yxx, 1, 0, 0);
Vector3_Comp3_RO (yxy, 1, 0, 1);
Vector3_Comp3_RW (yxz, 1, 0, 2);
Vector3_Comp3_RO (yyx, 1, 1, 0);
Vector3_Comp3_RO (yyy, 1, 1, 1);
Vector3_Comp3_RO (yyz, 1, 1, 2);
Vector3_Comp3_RW (yzx, 1, 2, 0);
Vector3_Comp3_RO (yzy, 1, 2, 1);
Vector3_Comp3_RO (yzz, 1, 2, 2);
Vector3_Comp3_RO (zxx, 2, 0, 0);
Vector3_Comp3_RW (zxy, 2, 0, 1);
Vector3_Comp3_RO (zxz, 2, 0, 2);
Vector3_Comp3_RW (zyx, 2, 1, 0);
Vector3_Comp3_RO (zyy, 2, 1, 1);
Vector3_Comp3_RO (zyz, 2, 1, 2);
Vector3_Comp3_RO (zzx, 2, 2, 0);
Vector3_Comp3_RO (zzy, 2, 2, 1);
Vector3_Comp3_RO (zzz, 2, 2, 2);
};
// undefine macros
#undef Vector2_AssignOp
#undef Vector3_AssignOp
#undef Vector2_AssignOps
#undef Vector3_AssignOps
#undef Vector2_CastOp
#undef Vector3_CastOp
#undef Vector2_Comp2_RO
#undef Vector3_Comp2_RO
#undef Vector3_Comp3_RO
#undef Vector2_Comp2_RW
#undef Vector3_Comp2_RW
#undef Vector3_Comp3_RW
// Vector2 operators
inline Vector2 operator + (Vector2 Src)
{
return (Src);
}
inline Vector2 operator - (Vector2 Src)
{
return (Vector2 (-Src.x, -Src.y));
}
inline Vector2 operator + (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x + Src2.x, Src1.y + Src2.y));
}
inline Vector2 operator - (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x - Src2.x, Src1.y - Src2.y));
}
inline Vector2 operator * (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x * Src2.x, Src1.y * Src2.y));
}
inline Vector2 operator / (Vector2 Src1, Vector2 Src2)
{
return (Vector2 (Src1.x / Src2.x, Src1.y / Src2.y));
}
inline Vector2 & operator += (Vector2 & Dst, Vector2 Src)
{
Dst.x += Src.x;
Dst.y += Src.y;
return (Dst);
}
inline Vector2 & operator -= (Vector2 & Dst, Vector2 Src)
{
Dst.x -= Src.x;
Dst.y -= Src.y;
return (Dst);
}
inline Vector2 & operator *= (Vector2 & Dst, Vector2 Src)
{
Dst.x *= Src.x;
Dst.y *= Src.y;
return (Dst);
}
inline Vector2 & operator /= (Vector2 & Dst, Vector2 Src)
{
Dst.x /= Src.x;
Dst.y /= Src.y;
return (Dst);
}
// Vector3 operators
inline Vector3 operator + (Vector3 Src)
{
return (Src);
}
inline Vector3 operator - (Vector3 Src)
{
return (Vector3 (-Src.x, -Src.y, -Src.z));
}
inline Vector3 operator + (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x + Src2.x, Src1.y + Src2.y, Src1.z + Src2.z));
}
inline Vector3 operator - (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x - Src2.x, Src1.y - Src2.y, Src1.z - Src2.z));
}
inline Vector3 operator * (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x * Src2.x, Src1.y * Src2.y, Src1.z * Src2.z));
}
inline Vector3 operator / (Vector3 Src1, Vector3 Src2)
{
return (Vector3 (Src1.x / Src2.x, Src1.y / Src2.y, Src1.z / Src2.z));
}
inline Vector3 & operator += (Vector3 & Dst, Vector3 Src)
{
Dst.x += Src.x;
Dst.y += Src.y;
Dst.z += Src.z;
return (Dst);
}
inline Vector3 & operator -= (Vector3 & Dst, Vector3 Src)
{
Dst.x -= Src.x;
Dst.y -= Src.y;
Dst.z -= Src.z;
return (Dst);
}
inline Vector3 & operator *= (Vector3 & Dst, Vector3 Src)
{
Dst.x *= Src.x;
Dst.y *= Src.y;
Dst.z *= Src.z;
return (Dst);
}
inline Vector3 & operator /= (Vector3 & Dst, Vector3 Src)
{
Dst.x /= Src.x;
Dst.y /= Src.y;
Dst.z /= Src.z;
return (Dst);
}
// additional operators for mixed types
inline Vector2 operator + (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) + Src2); }
inline Vector3 operator + (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) + Src2); }
inline Vector2 operator + (Vector2 Src1, float Src2) { return (Src1 + Vector2 (Src2, Src2)); }
inline Vector3 operator + (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) + Src2); }
inline Vector3 operator + (Vector3 Src1, float Src2) { return (Src1 + Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator + (Vector3 Src1, Vector2 Src2) { return (Src1 + Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 operator - (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) - Src2); }
inline Vector3 operator - (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) - Src2); }
inline Vector2 operator - (Vector2 Src1, float Src2) { return (Src1 - Vector2 (Src2, Src2)); }
inline Vector3 operator - (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) - Src2); }
inline Vector3 operator - (Vector3 Src1, float Src2) { return (Src1 - Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator - (Vector3 Src1, Vector2 Src2) { return (Src1 - Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 operator * (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) * Src2); }
inline Vector3 operator * (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) * Src2); }
inline Vector2 operator * (Vector2 Src1, float Src2) { return (Src1 * Vector2 (Src2, Src2)); }
inline Vector3 operator * (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) * Src2); }
inline Vector3 operator * (Vector3 Src1, float Src2) { return (Src1 * Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator * (Vector3 Src1, Vector2 Src2) { return (Src1 * Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 operator / (float Src1, Vector2 Src2) { return (Vector2 (Src1, Src1) / Src2); }
inline Vector3 operator / (float Src1, Vector3 Src2) { return (Vector3 (Src1, Src1, Src1) / Src2); }
inline Vector2 operator / (Vector2 Src1, float Src2) { return (Src1 / Vector2 (Src2, Src2)); }
inline Vector3 operator / (Vector2 Src1, Vector3 Src2) { return (Vector3 (Src1.x, Src1.y, Src1.y) / Src2); }
inline Vector3 operator / (Vector3 Src1, float Src2) { return (Src1 / Vector3 (Src2, Src2, Src2)); }
inline Vector3 operator / (Vector3 Src1, Vector2 Src2) { return (Src1 / Vector3 (Src2.x, Src2.y, Src2.y)); }
inline Vector2 & operator += (Vector2 & Dst, float Src) { return (Dst += Vector2 (Src, Src)); }
inline Vector3 & operator += (Vector3 & Dst, float Src) { return (Dst += Vector3 (Src, Src, Src)); }
inline Vector3 & operator += (Vector3 & Dst, Vector2 Src) { return (Dst += Vector3 (Src.x, Src.y, Src.y)); }
inline Vector2 & operator -= (Vector2 & Dst, float Src) { return (Dst -= Vector2 (Src, Src)); }
inline Vector3 & operator -= (Vector3 & Dst, float Src) { return (Dst -= Vector3 (Src, Src, Src)); }
inline Vector3 & operator -= (Vector3 & Dst, Vector2 Src) { return (Dst -= Vector3 (Src.x, Src.y, Src.y)); }
inline Vector2 & operator *= (Vector2 & Dst, float Src) { return (Dst *= Vector2 (Src, Src)); }
inline Vector3 & operator *= (Vector3 & Dst, float Src) { return (Dst *= Vector3 (Src, Src, Src)); }
inline Vector3 & operator *= (Vector3 & Dst, Vector2 Src) { return (Dst *= Vector3 (Src.x, Src.y, Src.y)); }
inline Vector2 & operator /= (Vector2 & Dst, float Src) { return (Dst /= Vector2 (Src, Src)); }
inline Vector3 & operator /= (Vector3 & Dst, float Src) { return (Dst /= Vector3 (Src, Src, Src)); }
inline Vector3 & operator /= (Vector3 & Dst, Vector2 Src) { return (Dst /= Vector3 (Src.x, Src.y, Src.y)); }
#endif // _INC_VECTORS_H_
Mein Problem ist jetzt, daß der Compiler mit seinen Optimierungen (ich habe alles durchprobiert, was die Performance steigern kann) nicht soviel rausholt, wie machbar ist. Zum Testen habe ich das Kreuzprodukt in diesen beiden Varianten genommen:
inline Vector3 cross1 (Vector3 v1, Vector3 v2)
{
Vector3 v;
v.x = v1.y * v2.z - v1.z * v2.y;
v.y = v1.z * v2.x - v1.x * v2.z;
v.z = v1.x * v2.y - v1.y * v2.x;
return (v);
}
inline Vector3 cross2 (Vector3 v1, Vector3 v2)
{
return (v1.yzx * v2.zxy - v1.zxy * v2.yzx);
}
Wenn ich jetzt in einer Schleife (ich habe dafür gesorgt, daß das Ergebnis nicht verworfen wird) 100.000.000 mal das Kreuzprodukt berechne, spüre ich einen deutlichen Unterschied zwischen den beiden Varianten, cross2 ist um einiges langsamer. Und das, obwohl die beiden Varianten mathematisch äquivalent sind (bzw. sein sollten, die Rundungsfehler sind mit und ohne Float Consistency bei beiden Varianten etwas anders) und es im fertigen Code in dieser Schleife keinen einzigen Call mehr gibt.
Hat jemand eine Idee, was ich direkt im Code noch tun kann? Außer dem Verzicht auf das Swizzling natürlich. Ich möchte jederzeit das Swizzling nutzen können und trotzdem die maximale Performance haben.
PS: holt der Compiler von VS .Net 2005 vielleicht (deutlich) mehr raus? Dann würde ich wohl auf lange Sicht umsteigen.