Browse Source

core: implement a quaternion class and tighten some vector operation rules

to avoid common programming errors.
legacy
Sam Hocevar sam 13 years ago
parent
commit
def84d569d
3 changed files with 166 additions and 80 deletions
  1. +17
    -24
      src/matrix.cpp
  2. +148
    -55
      src/matrix.h
  3. +1
    -1
      test/Makefile.am

+ 17
- 24
src/matrix.cpp View File

@@ -53,30 +53,6 @@ template<> vec3 cross(vec3 v1, vec3 v2)
v1.x * v2.y - v1.y * v2.x);
}

template<> vec2 normalize(vec2 v)
{
float norm = v.len();
if (!norm)
return vec2(0);
return v / norm;
}

template<> vec3 normalize(vec3 v)
{
float norm = v.len();
if (!norm)
return vec3(0);
return v / norm;
}

template<> vec4 normalize(vec4 v)
{
float norm = v.len();
if (!norm)
return vec4(0.0f);
return v / norm;
}

static inline float det3(float a, float b, float c,
float d, float e, float f,
float g, float h, float i)
@@ -151,6 +127,11 @@ template<> void ivec4::printf() const
Log::Debug("[ %i %i %i %i ]\n", x, y, z, w);
}

template<> void quat::printf() const
{
Log::Debug("[ %6.6f %6.6f %6.6f %6.6f ]\n", x, y, z, w);
}

template<> void mat4::printf() const
{
mat4 const &p = *this;
@@ -182,6 +163,12 @@ template<> std::ostream &operator<<(std::ostream &stream, ivec4 const &v)
<< v.z << ", " << v.w << ")";
}

template<> std::ostream &operator<<(std::ostream &stream, iquat const &v)
{
return stream << "(" << v.x << ", " << v.y << ", "
<< v.z << ", " << v.w << ")";
}

template<> std::ostream &operator<<(std::ostream &stream, vec2 const &v)
{
return stream << "(" << v.x << ", " << v.y << ")";
@@ -198,6 +185,12 @@ template<> std::ostream &operator<<(std::ostream &stream, vec4 const &v)
<< v.z << ", " << v.w << ")";
}

template<> std::ostream &operator<<(std::ostream &stream, quat const &v)
{
return stream << "(" << v.x << ", " << v.y << ", "
<< v.z << ", " << v.w << ")";
}

template<> std::ostream &operator<<(std::ostream &stream, mat4 const &m)
{
stream << "((" << m[0][0] << ", " << m[1][0]


+ 148
- 55
src/matrix.h View File

@@ -24,62 +24,60 @@
namespace lol
{

#define VECTOR_OP(elems, op) \
template<typename U> \
inline Vec##elems<T> operator op(Vec##elems<U> const &val) const \
#define VECTOR_OP(op) \
inline type_t operator op(type_t const &val) const \
{ \
Vec##elems<T> ret; \
for (int n = 0; n < elems; n++) \
type_t ret; \
for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
ret[n] = (*this)[n] op val[n]; \
return ret; \
} \
\
template<typename U> \
inline Vec##elems<T> operator op##=(Vec##elems<U> const &val) \
inline type_t operator op##=(type_t const &val) \
{ \
return *this = (*this) op val; \
}

#define BOOL_OP(elems, op, op2, ret) \
inline bool operator op(Vec##elems<T> const &val) const \
#define BOOL_OP(op, op2, ret) \
inline bool operator op(type_t const &val) const \
{ \
for (int n = 0; n < elems; n++) \
for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
if (!((*this)[n] op2 val[n])) \
return !ret; \
return ret; \
}

#define SCALAR_OP(elems, op) \
inline Vec##elems<T> operator op(T const &val) const \
#define SCALAR_OP(op) \
inline type_t operator op(T const &val) const \
{ \
Vec##elems<T> ret; \
for (int n = 0; n < elems; n++) \
type_t ret; \
for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
ret[n] = (*this)[n] op val; \
return ret; \
} \
\
inline Vec##elems<T> operator op##=(T const &val) \
inline type_t operator op##=(T const &val) \
{ \
return *this = (*this) op val; \
}

#define LINEAR_OPS(elems) \
#define LINEAR_OPS() \
inline T& operator[](int n) { return *(&x + n); } \
inline T const& operator[](int n) const { return *(&x + n); } \
\
VECTOR_OP(elems, -) \
VECTOR_OP(elems, +) \
VECTOR_OP(-) \
VECTOR_OP(+) \
\
BOOL_OP(elems, ==, ==, true) \
BOOL_OP(elems, !=, ==, false) \
BOOL_OP(==, ==, true) \
BOOL_OP(!=, ==, false) \
\
SCALAR_OP(elems, *) \
SCALAR_OP(elems, /) \
SCALAR_OP(*) \
SCALAR_OP(/) \
\
inline Vec##elems<T> operator -() const \
inline type_t operator -() const \
{ \
Vec##elems<T> ret; \
for (int n = 0; n < elems; n++) \
type_t ret; \
for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
ret[n] = -(*this)[n]; \
return ret; \
} \
@@ -87,7 +85,7 @@ namespace lol
inline T sqlen() const \
{ \
T acc = 0; \
for (int n = 0; n < elems; n++) \
for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
acc += (*this)[n] * (*this)[n]; \
return acc; \
} \
@@ -98,25 +96,52 @@ namespace lol
return sqrtf((float)sqlen()); \
} \
\
template<typename U> \
friend Vec##elems<U> normalize(Vec##elems<U>); \
\
void printf() const;

#define QUATERNION_OPS() \
inline type_t operator *(type_t const &val) const \
{ \
type_t ret; \
Vec3<T> v1(x, y, z); \
Vec3<T> v2(val.x, val.y, val.z); \
Vec3<T> v3 = cross(v1, v2) + w * v2 + val.w * v1; \
ret.x = v3.x; \
ret.y = v3.y; \
ret.z = v3.z; \
ret.w = w * val.w - dot(v1, v2); \
return ret; \
} \
\
inline type_t operator *=(type_t const &val) \
{ \
return *this = (*this) * val; \
} \
\
inline type_t operator ~() const \
{ \
type_t ret; \
for (int n = 0; n < 3; n++) \
ret[n] = -(*this)[n]; \
ret[3] = (*this)[3]; \
return ret; \
} \
\
inline T norm() const { return sqlen(); }

#define OTHER_OPS(elems) \
VECTOR_OP(elems, *) \
VECTOR_OP(elems, /) \
VECTOR_OP(*) \
VECTOR_OP(/) \
\
BOOL_OP(elems, <=, <=, true) \
BOOL_OP(elems, >=, >=, true) \
BOOL_OP(elems, <, <, true) \
BOOL_OP(elems, >, >, true) \
BOOL_OP(<=, <=, true) \
BOOL_OP(>=, >=, true) \
BOOL_OP(<, <, true) \
BOOL_OP(>, >, true) \
\
template<typename U> \
inline operator Vec##elems<U>() const \
{ \
Vec##elems<U> ret; \
for (int n = 0; n < elems; n++) \
for (size_t n = 0; n < sizeof(*this) / sizeof(T); n++) \
ret[n] = static_cast<U>((*this)[n]); \
return ret; \
} \
@@ -195,11 +220,13 @@ template <typename T> struct Vec4;

template <typename T> struct Vec2
{
typedef Vec2<T> type_t;

inline Vec2() { }
explicit inline Vec2(T val) { x = y = val; }
inline Vec2(T _x, T _y) { x = _x; y = _y; }

LINEAR_OPS(2)
LINEAR_OPS()
OTHER_OPS(2)

SWIZZLE22(x); SWIZZLE22(y);
@@ -232,13 +259,15 @@ typedef Vec2<uint64_t> u64vec2;

template <typename T> struct Vec3
{
typedef Vec3<T> type_t;

inline Vec3() { }
explicit inline Vec3(T val) { x = y = z = val; }
inline Vec3(T _x, T _y, T _z) { x = _x; y = _y; z = _z; }
inline Vec3(Vec2<T> _xy, T _z) { x = _xy.x; y = _xy.y; z = _z; }
inline Vec3(T _x, Vec2<T> _yz) { x = _x; y = _yz.x; z = _yz.y; }

LINEAR_OPS(3)
LINEAR_OPS()
OTHER_OPS(3)

SWIZZLE23(x); SWIZZLE23(y); SWIZZLE23(z);
@@ -275,6 +304,8 @@ typedef Vec3<uint64_t> u64vec3;

template <typename T> struct Vec4
{
typedef Vec4<T> type_t;

inline Vec4() { }
explicit inline Vec4(T val) : x(val), y(val), z(val), w(val) { }
inline Vec4(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) { }
@@ -285,7 +316,7 @@ template <typename T> struct Vec4
inline Vec4(Vec3<T> _xyz, T _w) : x(_xyz.x), y(_xyz.y), z(_xyz.z), w(_w) { }
inline Vec4(T _x, Vec3<T> _yzw) : x(_x), y(_yzw.x), z(_yzw.y), w(_yzw.z) { }

LINEAR_OPS(4)
LINEAR_OPS()
OTHER_OPS(4)

SWIZZLE24(x); SWIZZLE24(y); SWIZZLE24(z); SWIZZLE24(w);
@@ -314,30 +345,90 @@ typedef Vec4<uint32_t> uvec4;
typedef Vec4<int64_t> i64vec4;
typedef Vec4<uint64_t> u64vec4;

#define SCALAR_GLOBAL(elems, op, U) \
/*
* 4-element quaternions
*/

template <typename T> struct Quat
{
typedef Quat<T> type_t;

inline Quat() { }
inline Quat(T val) : x(0), y(0), z(0), w(val) { }
inline Quat(T _x, T _y, T _z, T _w) : x(_x), y(_y), z(_z), w(_w) { }

LINEAR_OPS()
QUATERNION_OPS()

#if !defined __ANDROID__
template<typename U>
friend std::ostream &operator<<(std::ostream &stream, Quat<U> const &v);
#endif

T x, y, z, w;
};

template<typename T>
static inline Quat<T> re(Quat<T> const &val)
{
return ~val / val.norm();
}

template<typename T>
static inline Quat<T> operator /(T x, Quat<T> const &y)
{
return x * re(y);
}

template<typename T>
static inline Quat<T> operator /(Quat<T> x, Quat<T> const &y)
{
return x * re(y);
}

typedef Quat<half> f16quat;
typedef Quat<float> quat;
typedef Quat<int8_t> i8quat;
typedef Quat<uint8_t> u8quat;
typedef Quat<int16_t> i16quat;
typedef Quat<uint16_t> u16quat;
typedef Quat<int32_t> iquat;
typedef Quat<uint32_t> uquat;
typedef Quat<int64_t> i64quat;
typedef Quat<uint64_t> u64quat;

/*
* Common operators for all vector types, including quaternions
*/

#define SCALAR_GLOBAL(tname, op, U) \
template<typename T> \
static inline Vec##elems<U> operator op(U const &val, \
Vec##elems<T> const &that) \
static inline tname<U> operator op(U const &val, tname<T> const &that) \
{ \
Vec##elems<U> ret; \
for (int n = 0; n < elems; n++) \
tname<U> ret; \
for (unsigned int n = 0; n < sizeof(that) / sizeof(that[0]); n++) \
ret[n] = val op that[n]; \
return ret; \
}

#define SCALAR_GLOBAL2(elems, op) \
SCALAR_GLOBAL(elems, op, int) \
SCALAR_GLOBAL(elems, op, float)
#define SCALAR_GLOBAL2(tname, op) \
SCALAR_GLOBAL(tname, op, int) \
SCALAR_GLOBAL(tname, op, float)

#define GLOBALS(elems) \
SCALAR_GLOBAL2(elems, -) \
SCALAR_GLOBAL2(elems, +) \
SCALAR_GLOBAL2(elems, *) \
SCALAR_GLOBAL2(elems, /)
#define GLOBALS(tname) \
SCALAR_GLOBAL2(tname, *) \
\
template<typename T> \
static inline tname<T> normalize(tname<T> const &val) \
{ \
T norm = val.len(); \
return norm ? val / norm : val * 0; \
}

GLOBALS(2)
GLOBALS(3)
GLOBALS(4)
GLOBALS(Vec2)
GLOBALS(Vec3)
GLOBALS(Vec4)
GLOBALS(Quat)

/*
* 4×4-element matrices
@@ -345,6 +436,8 @@ GLOBALS(4)

template <typename T> struct Mat4
{
typedef Mat4<T> type_t;

inline Mat4() { }
explicit inline Mat4(T val)
{


+ 1
- 1
test/Makefile.am View File

@@ -24,7 +24,7 @@ TESTS = testsuite

testsuite_SOURCES = testsuite.cpp \
unit/matrix.cpp unit/half.cpp unit/trig.cpp unit/build.cpp \
unit/real.cpp unit/image.cpp
unit/real.cpp unit/image.cpp unit/quat.cpp
testsuite_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@
testsuite_LDFLAGS = $(top_builddir)/src/liblol.a @LOL_LIBS@ @PIPI_LIBS@
testsuite_DEPENDENCIES = $(top_builddir)/src/liblol.a


Loading…
Cancel
Save