diff --git a/src/Makefile.am b/src/Makefile.am
index 6d2641d5..3bbe08e6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,7 +43,7 @@ liblolcore_headers = \
     lol/math/all.h \
     lol/math/functions.h lol/math/vector.h lol/math/half.h lol/math/real.h \
     lol/math/geometry.h lol/math/interp.h lol/math/rand.h lol/math/array2d.h \
-    lol/math/array3d.h lol/math/constants.h lol/math/matrix.h \
+    lol/math/array3d.h lol/math/constants.h lol/math/matrix.h lol/math/ops.h \
     lol/math/transform.h \
     \
     lol/algorithm/all.h \
diff --git a/src/lol/math/all.h b/src/lol/math/all.h
index 69b72c14..4b29957e 100644
--- a/src/lol/math/all.h
+++ b/src/lol/math/all.h
@@ -15,6 +15,7 @@
 #include <lol/math/functions.h>
 #include <lol/math/half.h>
 #include <lol/math/real.h>
+#include <lol/math/ops.h>
 #include <lol/math/vector.h>
 #include <lol/math/matrix.h>
 #include <lol/math/transform.h>
diff --git a/src/lol/math/half.h b/src/lol/math/half.h
index 39cffab5..65a46eec 100644
--- a/src/lol/math/half.h
+++ b/src/lol/math/half.h
@@ -116,6 +116,8 @@ public:
     uint16_t bits;
 };
 
+static_assert(sizeof(half) == 2, "sizeof(half) == 2");
+
 static inline half min(half a, half b) { return a < b ? a : b; }
 static inline half max(half a, half b) { return a > b ? a : b; }
 static inline float fmod(half a, half b)
diff --git a/src/lol/math/matrix.h b/src/lol/math/matrix.h
index 12c85ef6..b0d47dbc 100644
--- a/src/lol/math/matrix.h
+++ b/src/lol/math/matrix.h
@@ -33,8 +33,11 @@ namespace lol
  */
 
 template<typename T, int COLS, int ROWS>
-struct mat_t : public linear_ops::base
+struct mat_t
+  : public linear_ops::base<vec_t<T,ROWS>>
 {
+    static int const count = COLS;
+    typedef vec_t<T,ROWS> element;
     typedef mat_t<T,COLS,ROWS> type;
 
     inline mat_t() {}
@@ -59,8 +62,11 @@ private:
  */
 
 template <typename T>
-struct mat_t<T, 2, 2> : public linear_ops::base
+struct mat_t<T, 2, 2>
+  : public linear_ops::base<vec_t<T,2>>
 {
+    static int const count = 2;
+    typedef vec_t<T,2> element;
     typedef mat_t<T,2,2> type;
 
     inline mat_t() {}
@@ -119,13 +125,25 @@ private:
 #endif
 };
 
+static_assert(sizeof(i8mat2) == 4, "sizeof(i8mat2) == 4");
+static_assert(sizeof(i16mat2) == 8, "sizeof(i16mat2) == 8");
+static_assert(sizeof(imat2) == 16, "sizeof(imat2) == 16");
+static_assert(sizeof(i64mat2) == 32, "sizeof(i64mat2) == 32");
+
+static_assert(sizeof(f16mat2) == 8, "sizeof(f16mat2) == 8");
+static_assert(sizeof(mat2) == 16, "sizeof(mat2) == 16");
+static_assert(sizeof(dmat2) == 32, "sizeof(dmat2) == 32");
+
 /*
  * 3×3-element matrices
  */
 
 template <typename T>
-struct mat_t<T, 3, 3> : public linear_ops::base
+struct mat_t<T, 3, 3>
+  : public linear_ops::base<vec_t<T,3>>
 {
+    static int const count = 3;
+    typedef vec_t<T,3> element;
     typedef mat_t<T,3,3> type;
 
     inline mat_t() {}
@@ -230,13 +248,25 @@ private:
 #endif
 };
 
+static_assert(sizeof(i8mat3) == 9, "sizeof(i8mat3) == 9");
+static_assert(sizeof(i16mat3) == 18, "sizeof(i16mat3) == 18");
+static_assert(sizeof(imat3) == 36, "sizeof(imat3) == 36");
+static_assert(sizeof(i64mat3) == 72, "sizeof(i64mat3) == 72");
+
+static_assert(sizeof(f16mat3) == 18, "sizeof(f16mat3) == 18");
+static_assert(sizeof(mat3) == 36, "sizeof(mat3) == 36");
+static_assert(sizeof(dmat3) == 72, "sizeof(dmat3) == 72");
+
 /*
  * 4×4-element matrices
  */
 
 template <typename T>
-struct mat_t<T, 4, 4> : public linear_ops::base
+struct mat_t<T, 4, 4>
+  : public linear_ops::base<vec_t<T,4>>
 {
+    static int const count = 4;
+    typedef vec_t<T,4> element;
     typedef mat_t<T,4,4> type;
 
     inline mat_t() {}
@@ -388,6 +418,15 @@ private:
 #endif
 };
 
+static_assert(sizeof(i8mat4) == 16, "sizeof(i8mat4) == 16");
+static_assert(sizeof(i16mat4) == 32, "sizeof(i16mat4) == 32");
+static_assert(sizeof(imat4) == 64, "sizeof(imat4) == 64");
+static_assert(sizeof(i64mat4) == 128, "sizeof(i64mat4) == 128");
+
+static_assert(sizeof(f16mat4) == 32, "sizeof(f16mat4) == 32");
+static_assert(sizeof(mat4) == 64, "sizeof(mat4) == 64");
+static_assert(sizeof(dmat4) == 128, "sizeof(dmat4) == 128");
+
 template<typename T> T determinant(mat_t<T,2,2> const &);
 template<typename T> T determinant(mat_t<T,3,3> const &);
 template<typename T> T determinant(mat_t<T,4,4> const &);
@@ -406,53 +445,6 @@ static inline mat_t<T, ROWS, COLS> transpose(mat_t<T, COLS, ROWS> const &m)
     return ret;
 }
 
-/*
- * Addition/subtraction/unary
- */
-
-template<typename T, int COLS, int ROWS>
-static inline mat_t<T, COLS, ROWS> &operator +=(mat_t<T, COLS, ROWS> &a,
-                                                mat_t<T, COLS, ROWS> const &b)
-{
-    for (int i = 0; i < COLS; ++i)
-        a[i] += b[i];
-    return a;
-}
-
-template<typename T, int COLS, int ROWS>
-static inline mat_t<T, COLS, ROWS> operator +(mat_t<T, COLS, ROWS> const &a,
-                                              mat_t<T, COLS, ROWS> const &b)
-{
-    mat_t<T, COLS, ROWS> ret = a;
-    return ret += b;
-}
-
-template<typename T, int COLS, int ROWS>
-static inline mat_t<T, COLS, ROWS> &operator -=(mat_t<T, COLS, ROWS> &a,
-                                                mat_t<T, COLS, ROWS> const &b)
-{
-    for (int i = 0; i < COLS; ++i)
-        a[i] -= b[i];
-    return a;
-}
-
-template<typename T, int COLS, int ROWS>
-static inline mat_t<T, COLS, ROWS> operator -(mat_t<T, COLS, ROWS> const &a,
-                                              mat_t<T, COLS, ROWS> const &b)
-{
-    mat_t<T, COLS, ROWS> ret = a;
-    return ret -= b;
-}
-
-template<typename T, int COLS, int ROWS>
-static inline mat_t<T, COLS, ROWS> operator -(mat_t<T, COLS, ROWS> const &m)
-{
-    mat_t<T, COLS, ROWS> ret;
-    for (int i = 0; i < COLS; ++i)
-        ret[i] = -m[i];
-    return ret;
-}
-
 /*
  * Matrix-vector and vector-matrix multiplication
  */
diff --git a/src/lol/math/ops.h b/src/lol/math/ops.h
new file mode 100644
index 00000000..72f2379b
--- /dev/null
+++ b/src/lol/math/ops.h
@@ -0,0 +1,344 @@
+//
+// Lol Engine
+//
+// Copyright: (c) 2010-2014 Sam Hocevar <sam@hocevar.net>
+//   This program is free software; you can redistribute it and/or
+//   modify it under the terms of the Do What The Fuck You Want To
+//   Public License, Version 2, as published by Sam Hocevar. See
+//   http://www.wtfpl.net/ for more details.
+//
+
+//
+// Operations for vector classes
+// -----------------------------
+//
+
+#if !defined __LOL_MATH_OPS_H__
+#define __LOL_MATH_OPS_H__
+
+#include <ostream>
+#include <type_traits>
+
+#include <lol/math/half.h>
+#include <lol/math/real.h>
+
+/*
+ * Utility namespaces for traits -- this file uses a combination of
+ * ADL black magic and enable_if to ensure that only the expected type
+ * conversions are done.
+ */
+
+namespace lol
+{
+
+/*
+ * Operators for swizzled vectors. Since template deduction cannot be
+ * done for two arbitrary vec_t<> values, we help the compiler understand
+ * the expected type.
+ */
+
+namespace swizzle_ops
+{
+
+template<typename T, int SWIZZLE = FULL_SWIZZLE>
+struct base {};
+
+
+template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
+static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type operator ==(vec_t<T,N,SWIZZLE1> const &a,
+                               vec_t<T,N,SWIZZLE2> const &b)
+{
+    return vec_t<T,N>(a) == vec_t<T,N>(b);
+}
+
+template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
+static inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE || SWIZZLE2 != FULL_SWIZZLE, bool>::type operator !=(vec_t<T,N,SWIZZLE1> const &a,
+                               vec_t<T,N,SWIZZLE2> const &b)
+{
+    return vec_t<T,N>(a) != vec_t<T,N>(b);
+}
+
+#define LOL_SWIZZLE_V_VV_OP(op) \
+    template<typename T, int N, int SWIZZLE1, int SWIZZLE2> \
+    inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE \
+                                || SWIZZLE2 != FULL_SWIZZLE,vec_t<T,N>>::type \
+        operator op(vec_t<T,N,SWIZZLE1> const &a, \
+                    vec_t<T,N,SWIZZLE2> const &b) \
+    { \
+        return vec_t<T,N>(a) op vec_t<T,N>(b); \
+    } \
+    \
+    template<typename T, int N, int SWIZZLE> \
+    inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type & \
+        operator op##=(vec_t<T,N> &a, \
+                       vec_t<T,N,SWIZZLE> const &b) \
+    { \
+        return a op##= vec_t<T,N>(b); \
+    } \
+    \
+    template<typename T, int N, int SWIZZLE> \
+    inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type \
+        operator op(vec_t<T,N,SWIZZLE> a, T const &b) \
+    { \
+        return vec_t<T,N>(a) op b; \
+    }
+
+LOL_SWIZZLE_V_VV_OP(+)
+LOL_SWIZZLE_V_VV_OP(-)
+LOL_SWIZZLE_V_VV_OP(*)
+LOL_SWIZZLE_V_VV_OP(/)
+
+#undef LOL_SWIZZLE_V_VV_OP
+
+} /* namespace swizzle_ops */
+
+
+/*
+ * Linear operations: operators and functions that work on all types
+ * (vectors, matrices, quaternions...) such as addition or equality test.
+ *
+ * Others, e.g. multiplication, cannot be implemented here, since it should
+ * be implemented as per-component multiplication for vectors, and matrix
+ * product for matrices.
+ */
+
+namespace linear_ops
+{
+
+template<typename T>
+struct base {};
+
+/*
+ * Comparisons
+ */
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
+operator ==(V const &a, V const &b)
+{
+    for (int i = 0; i < V::count; ++i)
+        if (!(a[i] == b[i]))
+            return false;
+    return true;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
+operator !=(V const &a, V const &b)
+{
+    for (int i = 0; i < V::count; ++i)
+        if (a[i] != b[i])
+            return true;
+    return false;
+}
+
+/*
+ * Unary plus and minus
+ */
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator +(V const &v)
+{
+    return v;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator -(V const &v)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = -v[i];
+    return ret;
+}
+
+/*
+ * Addition and subtraction
+ */
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator +(V const &a, V const &b)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = a[i] + b[i];
+    return ret;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+&operator +=(V &a, V const &b)
+{
+    return a = a + b;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator -(V const &a, V const &b)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = a[i] - b[i];
+    return ret;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+&operator -=(V &a, V const &b)
+{
+    return a = a - b;
+}
+
+/*
+ * Multiplication by scalar (left)
+ */
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator *(typename V::element const &val, V const &a)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = val * a[i];
+    return ret;
+}
+
+/*
+ * Multiplication/division by scalar (right)
+ */
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator *(V const &a, typename V::element const &val)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = a[i] * val;
+    return ret;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type &
+operator *=(V &a, typename V::element const &val)
+{
+    return a = a * val;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator /(V const &a, typename V::element const &val)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = a[i] / val;
+    return ret;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type &
+operator /=(V &a, typename V::element const &val)
+{
+    return a = a / val;
+}
+
+} /* namespace linear_ops */
+
+
+/*
+ * Operations that work component-wise, such as comparisons or multiplication.
+ * This is only for vector types, as the other types (matrices, quaternions,
+ * complexes) have different meanings.
+ */
+
+namespace componentwise_ops
+{
+
+template<typename T>
+struct base {};
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator *(V const &a, V const &b)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = a[i] * b[i];
+    return ret;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+&operator *=(V &a, V const &b)
+{
+    return a = a * b;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+operator /(V const &a, V const &b)
+{
+    typename V::type ret;
+    for (int i = 0; i < V::count; ++i)
+        ret[i] = a[i] / b[i];
+    return ret;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, typename V::type>::type
+&operator /=(V &a, V const &b)
+{
+    return a = a / b;
+}
+
+/*
+ * Comparisons
+ */
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
+operator <(V const &a, V const &b)
+{
+    for (int i = 0; i < V::count; ++i)
+        if (!(a[i] < b[i]))
+            return false;
+    return true;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
+operator >(V const &a, V const &b)
+{
+    for (int i = 0; i < V::count; ++i)
+        if (!(a[i] > b[i]))
+            return false;
+    return true;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
+operator <=(V const &a, V const &b)
+{
+    for (int i = 0; i < V::count; ++i)
+        if (!(a[i] <= b[i]))
+            return false;
+    return true;
+}
+
+template<typename V>
+static inline typename std::enable_if<std::is_base_of<base<typename V::element>, V>::value, bool>::type
+operator >=(V const &a, V const &b)
+{
+    for (int i = 0; i < V::count; ++i)
+        if (!(a[i] >= b[i]))
+            return false;
+    return true;
+}
+
+} /* namespace componentwise_ops */
+
+} /* namespace lol */
+
+#endif // __LOL_MATH_OPS_H__
+
diff --git a/src/lol/math/transform.h b/src/lol/math/transform.h
index 0d191d88..33689fb2 100644
--- a/src/lol/math/transform.h
+++ b/src/lol/math/transform.h
@@ -30,8 +30,10 @@ namespace lol
  */
 
 template<typename T>
-struct cmplx_t : public linear_ops::base
+struct cmplx_t : public linear_ops::base<T>
 {
+    static int const count = 2;
+    typedef T element;
     typedef cmplx_t<T> type;
 
     inline constexpr cmplx_t() {}
@@ -43,7 +45,6 @@ struct cmplx_t : public linear_ops::base
       : x(z.x), y(z.y) {}
 
     LOL_COMMON_MEMBER_OPS(x)
-    LOL_NONVECTOR_MEMBER_OPS()
 
     inline cmplx_t<T> operator *(cmplx_t<T> const &val) const
     {
@@ -66,13 +67,24 @@ struct cmplx_t : public linear_ops::base
     T x, y;
 };
 
+static_assert(sizeof(i8cmplx) == 2, "sizeof(i8cmplx) == 2");
+static_assert(sizeof(i16cmplx) == 4, "sizeof(i16cmplx) == 4");
+static_assert(sizeof(icmplx) == 8, "sizeof(icmplx) == 8");
+static_assert(sizeof(i64cmplx) == 16, "sizeof(i64cmplx) == 16");
+
+static_assert(sizeof(f16cmplx) == 4, "sizeof(f16cmplx) == 4");
+static_assert(sizeof(cmplx) == 8, "sizeof(cmplx) == 8");
+static_assert(sizeof(dcmplx) == 16, "sizeof(dcmplx) == 16");
+
 /*
  * 4-element transforms: quaternions
  */
 
 template<typename T>
-struct quat_t : public linear_ops::base
+struct quat_t : public linear_ops::base<T>
 {
+    static int const count = 4;
+    typedef T element;
     typedef quat_t<T> type;
 
     /* Default constructor and copy constructor */
@@ -95,7 +107,6 @@ struct quat_t : public linear_ops::base
     explicit quat_t(mat_t<T,4,4> const &m);
 
     LOL_COMMON_MEMBER_OPS(w)
-    LOL_NONVECTOR_MEMBER_OPS()
 
     inline quat_t operator *(quat_t const &val) const
     {
@@ -210,6 +221,15 @@ struct quat_t : public linear_ops::base
     T w, x, y, z;
 };
 
+static_assert(sizeof(i8quat) == 4, "sizeof(i8quat) == 4");
+static_assert(sizeof(i16quat) == 8, "sizeof(i16quat) == 8");
+static_assert(sizeof(iquat) == 16, "sizeof(iquat) == 16");
+static_assert(sizeof(i64quat) == 32, "sizeof(i64quat) == 32");
+
+static_assert(sizeof(f16quat) == 8, "sizeof(f16quat) == 8");
+static_assert(sizeof(quat) == 16, "sizeof(quat) == 16");
+static_assert(sizeof(dquat) == 32, "sizeof(dquat) == 32");
+
 /*
  * Common operations on transforms
  */
diff --git a/src/lol/math/vector.h b/src/lol/math/vector.h
index f953c025..18ec8259 100644
--- a/src/lol/math/vector.h
+++ b/src/lol/math/vector.h
@@ -17,10 +17,10 @@
 #define __LOL_MATH_VECTOR_H__
 
 #include <ostream>
-#include <type_traits>
 
 #include <lol/math/half.h>
 #include <lol/math/real.h>
+#include <lol/math/ops.h>
 
 namespace lol
 {
@@ -35,169 +35,6 @@ namespace lol
 #   define _____ /* */
 #endif
 
-/*
- * Utility namespaces for traits
- */
-
-namespace swizzle_ops
-{
-
-
-
-}
-
-
-namespace linear_ops
-{
-
-struct base {};
-
-/*
- * Unary plus and minus
- */
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-operator +(V const &v)
-{
-    return v;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-operator -(V const &v)
-{
-    V ret;
-    for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i)
-        ret[i] = -v[i];
-    return ret;
-}
-
-/*
- * Addition and subtraction
- */
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-operator +(V const &a, V const &b)
-{
-    V ret;
-    for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i)
-        ret[i] = a[i] + b[i];
-    return ret;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-&operator +=(V &a, V const &b)
-{
-    return a = a + b;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-operator -(V const &a, V const &b)
-{
-    V ret;
-    for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i)
-        ret[i] = a[i] - b[i];
-    return ret;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-&operator -=(V &a, V const &b)
-{
-    return a = a - b;
-}
-
-} /* namespace linear_ops */
-
-namespace componentwise_ops
-{
-
-struct base {};
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-operator *(V const &a, V const &b)
-{
-    V ret;
-    for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i)
-        ret[i] = a[i] * b[i];
-    return ret;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-&operator *=(V &a, V const &b)
-{
-    return a = a * b;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-operator /(V const &a, V const &b)
-{
-    V ret;
-    for (size_t i = 0; i < sizeof(ret) / sizeof(ret[0]); ++i)
-        ret[i] = a[i] / b[i];
-    return ret;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, V>::type
-&operator /=(V &a, V const &b)
-{
-    return a = a / b;
-}
-
-/*
- * Comparisons
- */
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type
-operator <(V const &a, V const &b)
-{
-    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
-        if (!(a[i] < b[i]))
-            return false;
-    return true;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type
-operator >(V const &a, V const &b)
-{
-    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
-        if (!(a[i] > b[i]))
-            return false;
-    return true;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type
-operator <=(V const &a, V const &b)
-{
-    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
-        if (!(a[i] <= b[i]))
-            return false;
-    return true;
-}
-
-template<typename V>
-static inline typename std::enable_if<std::is_base_of<base, V>::value, bool>::type
-operator >=(V const &a, V const &b)
-{
-    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
-        if (!(a[i] >= b[i]))
-            return false;
-    return true;
-}
-
-} /* namespace componentwise_ops */
-
 /*
  * Magic vector swizzling (part 1/2)
  * These vectors are empty, but thanks to static_cast we can take their
@@ -214,7 +51,13 @@ operator >=(V const &a, V const &b)
 
 template<typename T, int N, int SWIZZLE>
 struct vec_t
+    /* MUST be a different base than e.g. vec_t<T,2> otherwise the unions
+     * in vec_t<T,2> with the same base will cause empty base optimisation
+     * failures. */
+  : public swizzle_ops::base<T, SWIZZLE>
 {
+    static int const count = N;
+    typedef T element;
     typedef vec_t<T,N> type;
 
     inline vec_t<T, N, SWIZZLE>& operator =(vec_t<T, N> that);
@@ -244,9 +87,11 @@ struct vec_t
  * swizzling. There's an override for N=2, N=3, N=4 that has swizzling. */
 template<typename T, int N>
 struct vec_t<T, N, FULL_SWIZZLE>
-  : public linear_ops::base,
-    public componentwise_ops::base
+  : public linear_ops::base<T>,
+    public componentwise_ops::base<T>
 {
+    static int const count = N;
+    typedef T element;
     typedef vec_t<T,N> type;
 
     inline T& operator[](size_t n) { return m_data[n]; }
@@ -260,30 +105,6 @@ private:
  * Helper macros for vector type member functions
  */
 
-#define LOL_V_VS_OP(op) \
-    friend inline type operator op(type const &a, T const &val) \
-    { \
-        type ret; \
-        for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \
-            ret[i] = a[i] op val; \
-        return ret; \
-    }
-
-#define LOL_V_VS_ASSIGN_OP(op) \
-    friend inline type operator op##=(type &a, T const &val) \
-    { \
-        return a = a op val; \
-    }
-
-#define LOL_B_VV_OP(op, op2, ret) \
-    friend inline bool operator op(type const &a, type const &b) \
-    { \
-        for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \
-            if (!(a[i] op2 b[i])) \
-                return !ret; \
-        return ret; \
-    }
-
 #define LOL_COMMON_MEMBER_OPS(first) \
     inline T& operator[](size_t n) { return (&this->first)[n]; } \
     inline T const& operator[](size_t n) const { return (&this->first)[n]; } \
@@ -291,37 +112,13 @@ private:
     /* Visual Studio insists on having an assignment operator. */ \
     inline type & operator =(type const &that) \
     { \
-        for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \
+        for (int i = 0; i < type::count; ++i) \
             (*this)[i] = that[i]; \
         return *this; \
     } \
     \
     void printf() const; \
-    String tostring() const; \
-    \
-    /* vec_t *(vec_t, scalar)
-     * vec_t /(vec_t, scalar)
-     * vec_t *=(vec_t, scalar)
-     * vec_t /=(vec_t, scalar) */ \
-    LOL_V_VS_OP(*) \
-    LOL_V_VS_OP(/) \
-    LOL_V_VS_ASSIGN_OP(*) \
-    LOL_V_VS_ASSIGN_OP(/) \
-    \
-    /* bool ==(vec_t, vec_t)
-     * bool !=(vec_t, vec_t) */ \
-    LOL_B_VV_OP(==, ==, true) \
-    LOL_B_VV_OP(!=, ==, false)
-
-#define LOL_NONVECTOR_MEMBER_OPS() \
-    /* vec_t *(scalar, vec_t) (no division, it works differently) */ \
-    friend inline type operator *(T const &val, type const &a) \
-    { \
-        type ret; \
-        for (size_t i = 0; i < sizeof(type) / sizeof(T); ++i) \
-            ret[i] = val * a[i]; \
-        return ret; \
-    }
+    String tostring() const;
 
 /*
  * 2-element vectors
@@ -329,9 +126,12 @@ private:
 
 template <typename T>
 struct vec_t<T,2>
-  : public linear_ops::base,
-    public componentwise_ops::base
+  : public swizzle_ops::base<T>,
+    public linear_ops::base<T>,
+    public componentwise_ops::base<T>
 {
+    static int const count = 2;
+    typedef T element;
     typedef vec_t<T,2> type;
 
     /* Default constructor, copy constructor, and destructor */
@@ -405,15 +205,27 @@ struct vec_t<T,2>
     };
 };
 
+static_assert(sizeof(i8vec2) == 2, "sizeof(i8vec2) == 2");
+static_assert(sizeof(i16vec2) == 4, "sizeof(i16vec2) == 4");
+static_assert(sizeof(ivec2) == 8, "sizeof(ivec2) == 8");
+static_assert(sizeof(i64vec2) == 16, "sizeof(i64vec2) == 16");
+
+static_assert(sizeof(f16vec2) == 4, "sizeof(f16vec2) == 4");
+static_assert(sizeof(vec2) == 8, "sizeof(vec2) == 8");
+static_assert(sizeof(dvec2) == 16, "sizeof(dvec2) == 16");
+
 /*
  * 3-element vectors
  */
 
 template <typename T>
 struct vec_t<T,3>
-  : public linear_ops::base,
-    public componentwise_ops::base
+  : public swizzle_ops::base<T>,
+    public linear_ops::base<T>,
+    public componentwise_ops::base<T>
 {
+    static int const count = 3;
+    typedef T element;
     typedef vec_t<T,3> type;
 
     /* Default constructor, copy constructor, and destructor */
@@ -617,15 +429,27 @@ struct vec_t<T,3>
     };
 };
 
+static_assert(sizeof(i8vec3) == 3, "sizeof(i8vec3) == 3");
+static_assert(sizeof(i16vec3) == 6, "sizeof(i16vec3) == 6");
+static_assert(sizeof(ivec3) == 12, "sizeof(ivec3) == 12");
+static_assert(sizeof(i64vec3) == 24, "sizeof(i64vec3) == 24");
+
+static_assert(sizeof(f16vec3) == 6, "sizeof(f16vec3) == 6");
+static_assert(sizeof(vec3) == 12, "sizeof(vec3) == 12");
+static_assert(sizeof(dvec3) == 24, "sizeof(dvec3) == 24");
+
 /*
  * 4-element vectors
  */
 
 template <typename T>
 struct vec_t<T,4>
-  : public linear_ops::base,
-    public componentwise_ops::base
+  : public swizzle_ops::base<T>,
+    public linear_ops::base<T>,
+    public componentwise_ops::base<T>
 {
+    static int const count = 4;
+    typedef T element;
     typedef vec_t<T,4> type;
 
     /* Default constructor, copy constructor, and destructor */
@@ -1022,68 +846,24 @@ struct vec_t<T,4>
     };
 };
 
-/*
- * Operators for swizzled vectors. Since template deduction cannot be
- * done for two arbitrary vec_t<> values, we help the compiler understand
- * the expected type.
- */
+static_assert(sizeof(i8vec4) == 4, "sizeof(i8vec4) == 4");
+static_assert(sizeof(i16vec4) == 8, "sizeof(i16vec4) == 8");
+static_assert(sizeof(ivec4) == 16, "sizeof(ivec4) == 16");
+static_assert(sizeof(i64vec4) == 32, "sizeof(i64vec4) == 32");
 
-template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
-static inline bool operator ==(vec_t<T,N,SWIZZLE1> const &a,
-                               vec_t<T,N,SWIZZLE2> const &b)
-{
-    for (size_t i = 0; i < N; ++i)
-        if (!(a[i] == b[i]))
-            return false;
-    return true;
-}
-
-template<typename T, int N, int SWIZZLE1, int SWIZZLE2>
-static inline bool operator !=(vec_t<T,N,SWIZZLE1> const &a,
-                               vec_t<T,N,SWIZZLE2> const &b)
-{
-    for (size_t i = 0; i < N; ++i)
-        if (a[i] != b[i])
-            return true;
-    return false;
-}
+static_assert(sizeof(f16vec4) == 8, "sizeof(f16vec4) == 8");
+static_assert(sizeof(vec4) == 16, "sizeof(vec4) == 16");
+static_assert(sizeof(dvec4) == 32, "sizeof(dvec4) == 32");
 
-#define LOL_SWIZZLE_V_VV_OP(op) \
-    template<typename T, int N, int SWIZZLE1, int SWIZZLE2> \
-    inline typename std::enable_if<SWIZZLE1 != FULL_SWIZZLE \
-                                || SWIZZLE2 != FULL_SWIZZLE,vec_t<T,N>>::type \
-        operator op(vec_t<T,N,SWIZZLE1> const &a, \
-                    vec_t<T,N,SWIZZLE2> const &b) \
-    { \
-        return vec_t<T,N>(a) op vec_t<T,N>(b); \
-    } \
-    \
-    template<typename T, int N, int SWIZZLE> \
-    inline typename std::enable_if<SWIZZLE != FULL_SWIZZLE,vec_t<T,N>>::type & \
-        operator op##=(vec_t<T,N> &a, \
-                       vec_t<T,N,SWIZZLE> const &b) \
-    { \
-        return a op##= vec_t<T,N>(b); \
-    } \
-    \
-    template<typename T, int N, int SWIZZLE> \
-    inline vec_t<T,N> operator op(vec_t<T,N,SWIZZLE> a, T const &b) \
-    { \
-        return vec_t<T,N>(a) op b; \
-    }
-
-LOL_SWIZZLE_V_VV_OP(+)
-LOL_SWIZZLE_V_VV_OP(-)
-LOL_SWIZZLE_V_VV_OP(*)
-LOL_SWIZZLE_V_VV_OP(/)
-
-#undef LOL_SWIZZLE_V_VV_OP
+/*
+ * vec_t *(scalar, vec_t)
+ */
 
 template<typename T, int N, int SWIZZLE>
 static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a)
 {
     vec_t<T,N> ret;
-    for (size_t i = 0; i < N; ++i)
+    for (int i = 0; i < N; ++i)
         ret[i] = val * a[i];
     return ret;
 }
@@ -1100,7 +880,7 @@ static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a)
     { \
         using lol::fun; \
         vec_t<T,N> ret; \
-        for (size_t i = 0; i < N; ++i) \
+        for (int i = 0; i < N; ++i) \
             ret[i] = fun(a[i], b[i]); \
         return ret; \
     } \
@@ -1110,7 +890,7 @@ static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a)
     { \
         using lol::fun; \
         vec_t<T,N> ret; \
-        for (size_t i = 0; i < N; ++i) \
+        for (int i = 0; i < N; ++i) \
             ret[i] = fun(a[i], b); \
         return ret; \
     } \
@@ -1120,7 +900,7 @@ static inline vec_t<T,N> operator *(T const &val, vec_t<T,N,SWIZZLE> const &a)
     { \
         using lol::fun; \
         vec_t<T,N> ret; \
-        for (size_t i = 0; i < N; ++i) \
+        for (int i = 0; i < N; ++i) \
             ret[i] = fun(a, b[i]); \
         return ret; \
     }
@@ -1200,7 +980,7 @@ static inline T dot(vec_t<T,N,SWIZZLE1> const &a,
                     vec_t<T,N,SWIZZLE2> const &b)
 {
     T ret(0);
-    for (size_t i = 0; i < N; ++i)
+    for (int i = 0; i < N; ++i)
         ret += a[i] * b[i];
     return ret;
 }
@@ -1224,7 +1004,7 @@ static inline vec_t<T,N> lerp(vec_t<T,N,SWIZZLE1> const &a,
                               T const &s)
 {
     vec_t<T,N> ret;
-    for (size_t i = 0; i < N; ++i)
+    for (int i = 0; i < N; ++i)
         ret[i] = a[i] + s * (b[i] - a[i]);
     return ret;
 }
@@ -1240,7 +1020,7 @@ template<typename T, int N, int SWIZZLE>
 static inline vec_t<T,N> fract(vec_t<T,N,SWIZZLE> const &a)
 {
     vec_t<T,N> ret;
-    for (size_t i = 0; i < N; ++i)
+    for (int i = 0; i < N; ++i)
         ret[i] = fract(a[i]);
     return ret;
 }
@@ -1256,7 +1036,7 @@ template<typename T, int N, int SWIZZLE>
 static inline vec_t<T,N> abs(vec_t<T,N,SWIZZLE> const &a)
 {
     vec_t<T,N> ret;
-    for (size_t i = 0; i < N; ++i)
+    for (int i = 0; i < N; ++i)
         ret[i] = lol::abs(a[i]);
     return ret;
 }
@@ -1265,7 +1045,7 @@ template<typename T, int N, int SWIZZLE>
 static inline vec_t<T,N> degrees(vec_t<T,N,SWIZZLE> const &a)
 {
     vec_t<T,N> ret;
-    for (size_t i = 0; i < N; ++i)
+    for (int i = 0; i < N; ++i)
         ret[i] = lol::degrees(a[i]);
     return ret;
 }
@@ -1274,7 +1054,7 @@ template<typename T, int N, int SWIZZLE>
 static inline vec_t<T,N> radians(vec_t<T,N,SWIZZLE> const &a)
 {
     vec_t<T,N> ret;
-    for (size_t i = 0; i < N; ++i)
+    for (int i = 0; i < N; ++i)
         ret[i] = lol::radians(a[i]);
     return ret;
 }
diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj
index b02b0c0d..485e6133 100644
--- a/src/lolcore.vcxproj
+++ b/src/lolcore.vcxproj
@@ -327,6 +327,7 @@
     <ClInclude Include="lol\math\half.h" />
     <ClInclude Include="lol\math\interp.h" />
     <ClInclude Include="lol\math\matrix.h" />
+    <ClInclude Include="lol\math\ops.h" />
     <ClInclude Include="lol\math\rand.h" />
     <ClInclude Include="lol\math\real.h" />
     <ClInclude Include="lol\math\remez.h" />
diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters
index 8185f8dc..3b8af4ce 100644
--- a/src/lolcore.vcxproj.filters
+++ b/src/lolcore.vcxproj.filters
@@ -441,6 +441,9 @@
     <ClInclude Include="lol\math\matrix.h">
       <Filter>lol\math</Filter>
     </ClInclude>
+    <ClInclude Include="lol\math\ops.h">
+      <Filter>lol\math</Filter>
+    </ClInclude>
     <ClInclude Include="lol\math\rand.h">
       <Filter>lol\math</Filter>
     </ClInclude>