Changeset View
Changeset View
Standalone View
Standalone View
0ad/source/maths/FixedVector3D.h
Show All 15 Lines | |||||
*/ | */ | ||||
#ifndef INCLUDED_FIXED_VECTOR3D | #ifndef INCLUDED_FIXED_VECTOR3D | ||||
#define INCLUDED_FIXED_VECTOR3D | #define INCLUDED_FIXED_VECTOR3D | ||||
#include "maths/Fixed.h" | #include "maths/Fixed.h" | ||||
#include "maths/Sqrt.h" | #include "maths/Sqrt.h" | ||||
class CFixedVector3D | class alignas(16) CFixedVector3D | ||||
{ | { | ||||
public: | fixed X, Y, Z; //made private; returning const reference should be fastER | ||||
fixed X, Y, Z; | mutable fixed L; //cache for Length() computation; must be mutable... | ||||
public: | |||||
///constructors, etc. | |||||
CFixedVector3D() { } | CFixedVector3D() { } | ||||
CFixedVector3D(fixed X, fixed Y, fixed Z) : X(X), Y(Y), Z(Z) | |||||
{ | |||||
MarkLengthUpdateIsRequired(); //this boils to a quick inline reg clear op | |||||
} | |||||
//virtual ~CFixedVector2D() {} //do not inherit with data augmentation | |||||
CFixedVector3D(fixed X, fixed Y, fixed Z) : X(X), Y(Y), Z(Z) { } | ///get functions | ||||
fixed const & getX() const { return X; } //this should be fastER than making | |||||
fixed const & getY() const { return Y; } //the members public, as many engine | |||||
fixed const & getZ() const { return Z; } //optimizations are subverted otherwise | |||||
///Not quite "set functions"; "get non-const ref" functions to minimize changes | |||||
fixed& Xref() | |||||
{ | |||||
MarkLengthUpdateIsRequired(); //this boils to a quick inline reg clear op | |||||
return X; | |||||
} | |||||
fixed& Yref() | |||||
{ | |||||
MarkLengthUpdateIsRequired(); | |||||
return Y; | |||||
} | |||||
fixed& Zref() | |||||
{ | |||||
MarkLengthUpdateIsRequired(); | |||||
return Z; | |||||
} | |||||
/// Vector equality | /// Vector equality | ||||
bool operator==(const CFixedVector3D& v) const | bool operator==(const CFixedVector3D& v) const | ||||
{ | { | ||||
return (X == v.X && Y == v.Y && Z == v.Z); | return (X == v.X && Y == v.Y && Z == v.Z); | ||||
} | } | ||||
/// Vector inequality | /// Vector inequality | ||||
Show All 19 Lines | public: | ||||
{ | { | ||||
return CFixedVector3D(-X, -Y, -Z); | return CFixedVector3D(-X, -Y, -Z); | ||||
} | } | ||||
/// Vector addition | /// Vector addition | ||||
CFixedVector3D& operator+=(const CFixedVector3D& v) | CFixedVector3D& operator+=(const CFixedVector3D& v) | ||||
{ | { | ||||
*this = *this + v; | *this = *this + v; | ||||
MarkLengthUpdateIsRequired(); | |||||
return *this; | return *this; | ||||
} | } | ||||
/// Vector subtraction | /// Vector subtraction | ||||
CFixedVector3D& operator-=(const CFixedVector3D& v) | CFixedVector3D& operator-=(const CFixedVector3D& v) | ||||
{ | { | ||||
*this = *this - v; | *this = *this - v; | ||||
MarkLengthUpdateIsRequired(); | |||||
return *this; | return *this; | ||||
} | } | ||||
/// Length returned from cached value if current; otherwise recalculated | |||||
fixed const & Length() const | |||||
{ | |||||
ConditionallyUpdateLength(); | |||||
return L; | |||||
} | |||||
/** | int CompareLength(const CFixedVector3D& other) const | ||||
* Returns the length of the vector. | { | ||||
* Will not overflow if the result can be represented as type 'fixed'. | ConditionallyUpdateLength(); | ||||
*/ | other.ConditionallyUpdateLength(); | ||||
fixed Length() const | int result = 0; | ||||
if ( L < other.L ) result = -1; | |||||
if ( other.L < L ) result = 1; | |||||
return result; | |||||
} | |||||
private: | |||||
void UnconditionallyUpdateLength() const //L is mutable | |||||
{ | { | ||||
// Do intermediate calculations with 64-bit ints to avoid overflows | // Do intermediate calculations with 64-bit ints to avoid overflows | ||||
u64 xx = SQUARE_U64_FIXED(X); | u64 xx = SQUARE_U64_FIXED(X); | ||||
u64 yy = SQUARE_U64_FIXED(Y); | u64 yy = SQUARE_U64_FIXED(Y); | ||||
u64 zz = SQUARE_U64_FIXED(Z); | u64 zz = SQUARE_U64_FIXED(Z); | ||||
u64 t = xx + yy; | u64 t = xx + yy; | ||||
CheckUnsignedAdditionOverflow(t, xx, L"Overflow in CFixedVector3D::Length() part 1") | CheckUnsignedAdditionOverflow(t, xx, L"Overflow in CFixedVector3D::Length() part 1") | ||||
u64 d2 = t + zz; | u64 d2 = t + zz; | ||||
CheckUnsignedAdditionOverflow(d2, t, L"Overflow in CFixedVector3D::Length() part 2") | CheckUnsignedAdditionOverflow(d2, t, L"Overflow in CFixedVector3D::Length() part 2") | ||||
u32 d = isqrt64(d2); | u32 d = isqrt64(d2); | ||||
CheckU32CastOverflow(d, i32, L"Overflow in CFixedVector3D::Length() part 3") | CheckU32CastOverflow(d, i32, L"Overflow in CFixedVector3D::Length() part 3") | ||||
fixed r; | |||||
r.SetInternalValue((i32)d); | L.SetInternalValue((i32)d); | ||||
return r; | } | ||||
void ConditionallyUpdateLength() const | |||||
{ | |||||
if( L.IsZero() && !(X.IsZero() && Y.IsZero() && Z.IsZero()) ) | |||||
UnconditionallyUpdateLength(); | |||||
} | |||||
void MarkLengthUpdateIsRequired() const //L is mutable | |||||
{ | |||||
L.SetInternalValue(0); | |||||
} | } | ||||
public: | |||||
/** | /** | ||||
* Normalize the vector so that length is close to 1. | * Normalize the vector so that length is close to 1. | ||||
* If length is 0, does nothing. | * If length is 0, does nothing. | ||||
*/ | */ | ||||
void Normalize() | void Normalize() | ||||
{ | { | ||||
fixed l = Length(); | ConditionallyUpdateLength(); | ||||
if (!l.IsZero()) | if (!L.IsZero()) | ||||
{ | { | ||||
X = X / l; | X = X/L; | ||||
Y = Y / l; | Y = Y/L; | ||||
Z = Z / l; | Z = Z/L; | ||||
UnconditionallyUpdateLength(); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Normalize the vector so that length is close to n. | * Normalize the vector so that length is close to n. | ||||
* If length is 0, does nothing. | * If length is 0, does nothing. | ||||
*/ | */ | ||||
void Normalize(fixed n) | void Normalize(fixed n) | ||||
{ | { | ||||
fixed l = Length(); | ConditionallyUpdateLength(); | ||||
if (!l.IsZero()) | if (!L.IsZero()) | ||||
{ | { | ||||
X = X.MulDiv(n, l); | X = X.MulDiv(n, L); | ||||
Y = Y.MulDiv(n, l); | Y = Y.MulDiv(n, L); | ||||
Z = Z.MulDiv(n, l); | Z = Z.MulDiv(n, L); | ||||
UnconditionallyUpdateLength(); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Compute the cross product of this vector with another. | * Compute the cross product of this vector with another. | ||||
*/ | */ | ||||
CFixedVector3D Cross(const CFixedVector3D& v) | CFixedVector3D Cross(const CFixedVector3D& v) const //DanW58: const added; it was missing | ||||
{ | { | ||||
i64 y_vz = MUL_I64_I32_I32(Y.GetInternalValue(), v.Z.GetInternalValue()); | i64 y_vz = MUL_I64_I32_I32(Y.GetInternalValue(), v.Z.GetInternalValue()); | ||||
i64 z_vy = MUL_I64_I32_I32(Z.GetInternalValue(), v.Y.GetInternalValue()); | i64 z_vy = MUL_I64_I32_I32(Z.GetInternalValue(), v.Y.GetInternalValue()); | ||||
CheckSignedSubtractionOverflow(i64, y_vz, z_vy, L"Overflow in CFixedVector3D::Cross() part 1", L"Underflow in CFixedVector3D::Cross() part 1") | CheckSignedSubtractionOverflow(i64, y_vz, z_vy, L"Overflow in CFixedVector3D::Cross() part 1", L"Underflow in CFixedVector3D::Cross() part 1") | ||||
i64 x = y_vz - z_vy; | i64 x = y_vz - z_vy; | ||||
x >>= fixed::fract_bits; | x >>= fixed::fract_bits; | ||||
i64 z_vx = MUL_I64_I32_I32(Z.GetInternalValue(), v.X.GetInternalValue()); | i64 z_vx = MUL_I64_I32_I32(Z.GetInternalValue(), v.X.GetInternalValue()); | ||||
Show All 16 Lines | CFixedVector3D Cross(const CFixedVector3D& v) const //DanW58: const added; it was missing | ||||
ret.Y.SetInternalValue((i32)y); | ret.Y.SetInternalValue((i32)y); | ||||
ret.Z.SetInternalValue((i32)z); | ret.Z.SetInternalValue((i32)z); | ||||
return ret; | return ret; | ||||
} | } | ||||
/** | /** | ||||
* Compute the dot product of this vector with another. | * Compute the dot product of this vector with another. | ||||
*/ | */ | ||||
fixed Dot(const CFixedVector3D& v) | fixed Dot(const CFixedVector3D& v) const //DanW58: const added; it was missing | ||||
{ | { | ||||
i64 x = MUL_I64_I32_I32(X.GetInternalValue(), v.X.GetInternalValue()); | i64 x = MUL_I64_I32_I32(X.GetInternalValue(), v.X.GetInternalValue()); | ||||
i64 y = MUL_I64_I32_I32(Y.GetInternalValue(), v.Y.GetInternalValue()); | i64 y = MUL_I64_I32_I32(Y.GetInternalValue(), v.Y.GetInternalValue()); | ||||
i64 z = MUL_I64_I32_I32(Z.GetInternalValue(), v.Z.GetInternalValue()); | i64 z = MUL_I64_I32_I32(Z.GetInternalValue(), v.Z.GetInternalValue()); | ||||
CheckSignedAdditionOverflow(i64, x, y, L"Overflow in CFixedVector3D::Dot() part 1", L"Underflow in CFixedVector3D::Dot() part 1") | CheckSignedAdditionOverflow(i64, x, y, L"Overflow in CFixedVector3D::Dot() part 1", L"Underflow in CFixedVector3D::Dot() part 1") | ||||
i64 t = x + y; | i64 t = x + y; | ||||
CheckSignedAdditionOverflow(i64, t, z, L"Overflow in CFixedVector3D::Dot() part 2", L"Underflow in CFixedVector3D::Dot() part 2") | CheckSignedAdditionOverflow(i64, t, z, L"Overflow in CFixedVector3D::Dot() part 2", L"Underflow in CFixedVector3D::Dot() part 2") | ||||
i64 sum = t + z; | i64 sum = t + z; | ||||
sum >>= fixed::fract_bits; | sum >>= fixed::fract_bits; | ||||
CheckCastOverflow(sum, i32, L"Overflow in CFixedVector3D::Dot() part 3", L"Underflow in CFixedVector3D::Dot() part 3") | CheckCastOverflow(sum, i32, L"Overflow in CFixedVector3D::Dot() part 3", L"Underflow in CFixedVector3D::Dot() part 3") | ||||
fixed ret; | fixed ret; | ||||
ret.SetInternalValue((i32)sum); | ret.SetInternalValue((i32)sum); | ||||
return ret; | return ret; | ||||
} | } | ||||
}; | }; | ||||
#endif // INCLUDED_FIXED_VECTOR3D | #endif // INCLUDED_FIXED_VECTOR3D |
Wildfire Games · Phabricator