Bläddra i källkod

Math: Add the new WIP vector class

Panagiotis Christopoulos Charitos 1 vecka sedan
förälder
incheckning
14ecc39d1a
5 ändrade filer med 1918 tillägg och 3 borttagningar
  1. 1 0
      AnKi/Math.h
  2. 73 0
      AnKi/Math/GenVecSwizzles.py
  3. 1821 0
      AnKi/Math/Vec2.h
  4. 2 3
      AnKi/Resource/ResourceFilesystem.cpp
  5. 21 0
      Tests/Script/LuaBinder.cpp

+ 1 - 0
AnKi/Math.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <AnKi/Math/Vec.h>
+#include <AnKi/Math/Vec2.h>
 #include <AnKi/Math/Mat.h>
 #include <AnKi/Math/Quat.h>
 #include <AnKi/Math/Euler.h>

+ 73 - 0
AnKi/Math/GenVecSwizzles.py

@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+"""
+Generate all valid HLSL swizzles for float2, float3 and float4.
+Rules used:
+ - float2: components = x, y
+ - float3: components = x, y, z
+ - float4: components = x, y, z, w
+ - Swizzle lengths: 1..4 (HLSL allows swizzles up to length 4)
+ - Repetition and any ordering allowed, but only components that exist for the given vector type
+
+Outputs the swizzles to stdout and writes them to files:
+ - swizzles_float2.txt
+ - swizzles_float3.txt
+ - swizzles_float4.txt
+
+Quick usage: python3 hlsl_swizzles.py
+"""
+from itertools import product
+
+VECTOR_COMPONENTS = {
+    'float2': 'xy',
+    'float3': 'xyz',
+    'float4': 'xyzw',
+}
+
+MAX_SWIZZLE_LEN = 4
+
+
+def comp_to_index(c):
+    if c == "x": return "0"
+    elif c == "y": return "1"
+    elif c == "z": return "2"
+    else: return "3"
+
+
+def swizzle_to_indices(p):
+    txt = ""
+    for i in range(len(p)):
+        txt += comp_to_index(p[i]) + (", " if i < len(p) - 1 else "")
+    return txt
+
+
+def generate_swizzles(components: str, max_len: int = 4):
+    """Yield swizzle strings using only the provided components, lengths 1..max_len."""
+    comp_count = len(components)
+    for L in range(1, max_len + 1):
+        for p in product(components, repeat=L):
+            if len(p) > 1:
+            	yield "TVecSwizzledData<T, {}, {}> {};".format(comp_count, swizzle_to_indices(p), ''.join(p))
+
+
+if __name__ == '__main__':
+    totals = {}
+    for vt, comps in VECTOR_COMPONENTS.items():
+        swizzles = list(generate_swizzles(comps, MAX_SWIZZLE_LEN))
+        totals[vt] = len(swizzles)
+        # Print short summary
+        print(f"{vt}: {len(swizzles)} swizzles (components: {', '.join(comps)})")
+        # Optionally group by length — small readable output
+        by_len = {}
+        for s in swizzles:
+            by_len.setdefault(len(s), []).append(s)
+        for L in sorted(by_len):
+            print(f"  len={L}: {len(by_len[L])} -> example: {', '.join(by_len[L][:8])}{'...' if len(by_len[L])>8 else ''}")
+        # write full list to file
+        fname = f"swizzles_{vt}.txt"
+        with open(fname, 'w') as f:
+            for s in swizzles:
+                f.write(s + '\n')
+        print(f"  full list written to: {fname}\n")
+
+    total_all = sum(totals.values())
+    print(f"Total swizzles generated: {total_all}")

+ 1821 - 0
AnKi/Math/Vec2.h

@@ -0,0 +1,1821 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Math/Common.h>
+#include <AnKi/Util/F16.h>
+
+namespace anki {
+namespace v2 {
+
+template<typename T, U32 kComponentCount>
+class TVec;
+
+template<typename T, U32 kComponentCount, U32... kIndices>
+class TVecSwizzledData
+{
+public:
+	static constexpr U32 kIndexCount = sizeof...(kIndices);
+
+	using SwizzledVec = TVec<T, kIndexCount>;
+	using MainVec = TVec<T, kComponentCount>;
+
+	// For doing something like this: v4.xw = Vec2(1.0f)
+	MainVec& operator=(SwizzledVec in) requires(kComponentCount >= kIndexCount)
+	{
+		const U32 indices[] = {kIndices...};
+		for(U32 i = 0; i < kIndexCount; ++i)
+		{
+			m_arr[indices[i]] = in.m_arr[i];
+		}
+		return *reinterpret_cast<MainVec*>(this);
+	}
+
+	// For doing something like this: v2 = v4.xw
+	operator SwizzledVec() const
+	{
+		SwizzledVec vec;
+		const U32 indices[] = {kIndices...};
+		for(U32 i = 0; i < kIndexCount; ++i)
+		{
+			vec.m_arr[i] = m_arr[indices[i]];
+		}
+		return vec;
+	}
+
+private:
+	T m_arr[kComponentCount];
+};
+
+// Note: kSpecialConst is not of type T because some compilers don't like floats as template constants
+template<typename T, U32 kComponentCount, U32 kSpecialConst>
+class TVec4SpecialData
+{
+public:
+	using OutVec = TVec<T, 4>;
+
+	operator OutVec() const
+	{
+		OutVec vec;
+		for(U32 i = 0; i < kComponentCount; ++i)
+		{
+			vec.m_arr[i] = m_arr[i];
+		}
+		vec.m_arr[3] = T(kSpecialConst);
+		return vec;
+	}
+
+private:
+	T m_arr[kComponentCount];
+};
+
+template<typename T, U32 kComponentCount>
+class TVecSimdData
+{
+public:
+	T m_simd[kComponentCount];
+};
+
+template<typename T>
+class TVecSimdData<T, 4>
+{
+public:
+#if ANKI_SIMD_SSE
+	__m128 m_simd;
+#elif ANKI_SIMD_NEON
+	float32x4_t m_simd;
+#else
+	T m_simd[4];
+#endif
+};
+
+// Skip some warnings cause we really nead anonymous structs inside unions
+#if ANKI_COMPILER_MSVC
+#	pragma warning(push)
+#	pragma warning(disable : 4201)
+#elif ANKI_COMPILER_GCC_COMPATIBLE
+#	pragma GCC diagnostic push
+#	pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
+#	pragma GCC diagnostic ignored "-Wnested-anon-types"
+#endif
+
+template<typename T, U32 kComponentCount>
+class TVecData;
+
+// Data specializations
+
+template<typename T>
+class TVecData<T, 2>
+{
+public:
+	using Simd = Array<T, 2>;
+
+	union
+	{
+		struct
+		{
+			T x;
+			T y;
+		};
+
+		T m_carr[2];
+		Array<T, 2> m_arr;
+		Simd m_simd;
+
+		TVecSwizzledData<T, 2, 0, 0> xx;
+		TVecSwizzledData<T, 2, 0, 1> xy;
+		TVecSwizzledData<T, 2, 1, 0> yx;
+		TVecSwizzledData<T, 2, 1, 1> yy;
+		TVecSwizzledData<T, 2, 0, 0, 0> xxx;
+		TVecSwizzledData<T, 2, 0, 0, 1> xxy;
+		TVecSwizzledData<T, 2, 0, 1, 0> xyx;
+		TVecSwizzledData<T, 2, 0, 1, 1> xyy;
+		TVecSwizzledData<T, 2, 1, 0, 0> yxx;
+		TVecSwizzledData<T, 2, 1, 0, 1> yxy;
+		TVecSwizzledData<T, 2, 1, 1, 0> yyx;
+		TVecSwizzledData<T, 2, 1, 1, 1> yyy;
+		TVecSwizzledData<T, 2, 0, 0, 0, 0> xxxx;
+		TVecSwizzledData<T, 2, 0, 0, 0, 1> xxxy;
+		TVecSwizzledData<T, 2, 0, 0, 1, 0> xxyx;
+		TVecSwizzledData<T, 2, 0, 0, 1, 1> xxyy;
+		TVecSwizzledData<T, 2, 0, 1, 0, 0> xyxx;
+		TVecSwizzledData<T, 2, 0, 1, 0, 1> xyxy;
+		TVecSwizzledData<T, 2, 0, 1, 1, 0> xyyx;
+		TVecSwizzledData<T, 2, 0, 1, 1, 1> xyyy;
+		TVecSwizzledData<T, 2, 1, 0, 0, 0> yxxx;
+		TVecSwizzledData<T, 2, 1, 0, 0, 1> yxxy;
+		TVecSwizzledData<T, 2, 1, 0, 1, 0> yxyx;
+		TVecSwizzledData<T, 2, 1, 0, 1, 1> yxyy;
+		TVecSwizzledData<T, 2, 1, 1, 0, 0> yyxx;
+		TVecSwizzledData<T, 2, 1, 1, 0, 1> yyxy;
+		TVecSwizzledData<T, 2, 1, 1, 1, 0> yyyx;
+		TVecSwizzledData<T, 2, 1, 1, 1, 1> yyyy;
+	};
+};
+
+template<typename T>
+class TVecData<T, 3>
+{
+public:
+	using Simd = Array<T, 3>;
+
+	union
+	{
+		struct
+		{
+			T x;
+			T y;
+			T z;
+		};
+
+		T m_carr[3];
+		Array<T, 3> m_arr;
+		Simd m_simd;
+
+		TVec4SpecialData<T, 3, 0> xyz0;
+		TVec4SpecialData<T, 3, 1> xyz1;
+
+		TVecSwizzledData<T, 3, 0, 0> xx;
+		TVecSwizzledData<T, 3, 0, 1> xy;
+		TVecSwizzledData<T, 3, 0, 2> xz;
+		TVecSwizzledData<T, 3, 1, 0> yx;
+		TVecSwizzledData<T, 3, 1, 1> yy;
+		TVecSwizzledData<T, 3, 1, 2> yz;
+		TVecSwizzledData<T, 3, 2, 0> zx;
+		TVecSwizzledData<T, 3, 2, 1> zy;
+		TVecSwizzledData<T, 3, 2, 2> zz;
+		TVecSwizzledData<T, 3, 0, 0, 0> xxx;
+		TVecSwizzledData<T, 3, 0, 0, 1> xxy;
+		TVecSwizzledData<T, 3, 0, 0, 2> xxz;
+		TVecSwizzledData<T, 3, 0, 1, 0> xyx;
+		TVecSwizzledData<T, 3, 0, 1, 1> xyy;
+		TVecSwizzledData<T, 3, 0, 1, 2> xyz;
+		TVecSwizzledData<T, 3, 0, 2, 0> xzx;
+		TVecSwizzledData<T, 3, 0, 2, 1> xzy;
+		TVecSwizzledData<T, 3, 0, 2, 2> xzz;
+		TVecSwizzledData<T, 3, 1, 0, 0> yxx;
+		TVecSwizzledData<T, 3, 1, 0, 1> yxy;
+		TVecSwizzledData<T, 3, 1, 0, 2> yxz;
+		TVecSwizzledData<T, 3, 1, 1, 0> yyx;
+		TVecSwizzledData<T, 3, 1, 1, 1> yyy;
+		TVecSwizzledData<T, 3, 1, 1, 2> yyz;
+		TVecSwizzledData<T, 3, 1, 2, 0> yzx;
+		TVecSwizzledData<T, 3, 1, 2, 1> yzy;
+		TVecSwizzledData<T, 3, 1, 2, 2> yzz;
+		TVecSwizzledData<T, 3, 2, 0, 0> zxx;
+		TVecSwizzledData<T, 3, 2, 0, 1> zxy;
+		TVecSwizzledData<T, 3, 2, 0, 2> zxz;
+		TVecSwizzledData<T, 3, 2, 1, 0> zyx;
+		TVecSwizzledData<T, 3, 2, 1, 1> zyy;
+		TVecSwizzledData<T, 3, 2, 1, 2> zyz;
+		TVecSwizzledData<T, 3, 2, 2, 0> zzx;
+		TVecSwizzledData<T, 3, 2, 2, 1> zzy;
+		TVecSwizzledData<T, 3, 2, 2, 2> zzz;
+		TVecSwizzledData<T, 3, 0, 0, 0, 0> xxxx;
+		TVecSwizzledData<T, 3, 0, 0, 0, 1> xxxy;
+		TVecSwizzledData<T, 3, 0, 0, 0, 2> xxxz;
+		TVecSwizzledData<T, 3, 0, 0, 1, 0> xxyx;
+		TVecSwizzledData<T, 3, 0, 0, 1, 1> xxyy;
+		TVecSwizzledData<T, 3, 0, 0, 1, 2> xxyz;
+		TVecSwizzledData<T, 3, 0, 0, 2, 0> xxzx;
+		TVecSwizzledData<T, 3, 0, 0, 2, 1> xxzy;
+		TVecSwizzledData<T, 3, 0, 0, 2, 2> xxzz;
+		TVecSwizzledData<T, 3, 0, 1, 0, 0> xyxx;
+		TVecSwizzledData<T, 3, 0, 1, 0, 1> xyxy;
+		TVecSwizzledData<T, 3, 0, 1, 0, 2> xyxz;
+		TVecSwizzledData<T, 3, 0, 1, 1, 0> xyyx;
+		TVecSwizzledData<T, 3, 0, 1, 1, 1> xyyy;
+		TVecSwizzledData<T, 3, 0, 1, 1, 2> xyyz;
+		TVecSwizzledData<T, 3, 0, 1, 2, 0> xyzx;
+		TVecSwizzledData<T, 3, 0, 1, 2, 1> xyzy;
+		TVecSwizzledData<T, 3, 0, 1, 2, 2> xyzz;
+		TVecSwizzledData<T, 3, 0, 2, 0, 0> xzxx;
+		TVecSwizzledData<T, 3, 0, 2, 0, 1> xzxy;
+		TVecSwizzledData<T, 3, 0, 2, 0, 2> xzxz;
+		TVecSwizzledData<T, 3, 0, 2, 1, 0> xzyx;
+		TVecSwizzledData<T, 3, 0, 2, 1, 1> xzyy;
+		TVecSwizzledData<T, 3, 0, 2, 1, 2> xzyz;
+		TVecSwizzledData<T, 3, 0, 2, 2, 0> xzzx;
+		TVecSwizzledData<T, 3, 0, 2, 2, 1> xzzy;
+		TVecSwizzledData<T, 3, 0, 2, 2, 2> xzzz;
+		TVecSwizzledData<T, 3, 1, 0, 0, 0> yxxx;
+		TVecSwizzledData<T, 3, 1, 0, 0, 1> yxxy;
+		TVecSwizzledData<T, 3, 1, 0, 0, 2> yxxz;
+		TVecSwizzledData<T, 3, 1, 0, 1, 0> yxyx;
+		TVecSwizzledData<T, 3, 1, 0, 1, 1> yxyy;
+		TVecSwizzledData<T, 3, 1, 0, 1, 2> yxyz;
+		TVecSwizzledData<T, 3, 1, 0, 2, 0> yxzx;
+		TVecSwizzledData<T, 3, 1, 0, 2, 1> yxzy;
+		TVecSwizzledData<T, 3, 1, 0, 2, 2> yxzz;
+		TVecSwizzledData<T, 3, 1, 1, 0, 0> yyxx;
+		TVecSwizzledData<T, 3, 1, 1, 0, 1> yyxy;
+		TVecSwizzledData<T, 3, 1, 1, 0, 2> yyxz;
+		TVecSwizzledData<T, 3, 1, 1, 1, 0> yyyx;
+		TVecSwizzledData<T, 3, 1, 1, 1, 1> yyyy;
+		TVecSwizzledData<T, 3, 1, 1, 1, 2> yyyz;
+		TVecSwizzledData<T, 3, 1, 1, 2, 0> yyzx;
+		TVecSwizzledData<T, 3, 1, 1, 2, 1> yyzy;
+		TVecSwizzledData<T, 3, 1, 1, 2, 2> yyzz;
+		TVecSwizzledData<T, 3, 1, 2, 0, 0> yzxx;
+		TVecSwizzledData<T, 3, 1, 2, 0, 1> yzxy;
+		TVecSwizzledData<T, 3, 1, 2, 0, 2> yzxz;
+		TVecSwizzledData<T, 3, 1, 2, 1, 0> yzyx;
+		TVecSwizzledData<T, 3, 1, 2, 1, 1> yzyy;
+		TVecSwizzledData<T, 3, 1, 2, 1, 2> yzyz;
+		TVecSwizzledData<T, 3, 1, 2, 2, 0> yzzx;
+		TVecSwizzledData<T, 3, 1, 2, 2, 1> yzzy;
+		TVecSwizzledData<T, 3, 1, 2, 2, 2> yzzz;
+		TVecSwizzledData<T, 3, 2, 0, 0, 0> zxxx;
+		TVecSwizzledData<T, 3, 2, 0, 0, 1> zxxy;
+		TVecSwizzledData<T, 3, 2, 0, 0, 2> zxxz;
+		TVecSwizzledData<T, 3, 2, 0, 1, 0> zxyx;
+		TVecSwizzledData<T, 3, 2, 0, 1, 1> zxyy;
+		TVecSwizzledData<T, 3, 2, 0, 1, 2> zxyz;
+		TVecSwizzledData<T, 3, 2, 0, 2, 0> zxzx;
+		TVecSwizzledData<T, 3, 2, 0, 2, 1> zxzy;
+		TVecSwizzledData<T, 3, 2, 0, 2, 2> zxzz;
+		TVecSwizzledData<T, 3, 2, 1, 0, 0> zyxx;
+		TVecSwizzledData<T, 3, 2, 1, 0, 1> zyxy;
+		TVecSwizzledData<T, 3, 2, 1, 0, 2> zyxz;
+		TVecSwizzledData<T, 3, 2, 1, 1, 0> zyyx;
+		TVecSwizzledData<T, 3, 2, 1, 1, 1> zyyy;
+		TVecSwizzledData<T, 3, 2, 1, 1, 2> zyyz;
+		TVecSwizzledData<T, 3, 2, 1, 2, 0> zyzx;
+		TVecSwizzledData<T, 3, 2, 1, 2, 1> zyzy;
+		TVecSwizzledData<T, 3, 2, 1, 2, 2> zyzz;
+		TVecSwizzledData<T, 3, 2, 2, 0, 0> zzxx;
+		TVecSwizzledData<T, 3, 2, 2, 0, 1> zzxy;
+		TVecSwizzledData<T, 3, 2, 2, 0, 2> zzxz;
+		TVecSwizzledData<T, 3, 2, 2, 1, 0> zzyx;
+		TVecSwizzledData<T, 3, 2, 2, 1, 1> zzyy;
+		TVecSwizzledData<T, 3, 2, 2, 1, 2> zzyz;
+		TVecSwizzledData<T, 3, 2, 2, 2, 0> zzzx;
+		TVecSwizzledData<T, 3, 2, 2, 2, 1> zzzy;
+		TVecSwizzledData<T, 3, 2, 2, 2, 2> zzzz;
+	};
+};
+
+template<typename T>
+class TVecData<T, 4>
+{
+public:
+#if ANKI_SIMD_SSE
+	using Simd = __m128;
+#elif ANKI_SIMD_NEON
+	using Simd = float32x4_t;
+#endif
+
+	union
+	{
+		struct
+		{
+			T x;
+			T y;
+			T z;
+			T w;
+		};
+
+		T m_carr[4];
+		Array<T, 4> m_arr;
+		Simd m_simd;
+
+		TVec4SpecialData<T, 4, 0> xyz0;
+		TVec4SpecialData<T, 4, 1> xyz1;
+
+		TVecSwizzledData<T, 4, 0, 0> xx;
+		TVecSwizzledData<T, 4, 0, 1> xy;
+		TVecSwizzledData<T, 4, 0, 2> xz;
+		TVecSwizzledData<T, 4, 0, 3> xw;
+		TVecSwizzledData<T, 4, 1, 0> yx;
+		TVecSwizzledData<T, 4, 1, 1> yy;
+		TVecSwizzledData<T, 4, 1, 2> yz;
+		TVecSwizzledData<T, 4, 1, 3> yw;
+		TVecSwizzledData<T, 4, 2, 0> zx;
+		TVecSwizzledData<T, 4, 2, 1> zy;
+		TVecSwizzledData<T, 4, 2, 2> zz;
+		TVecSwizzledData<T, 4, 2, 3> zw;
+		TVecSwizzledData<T, 4, 3, 0> wx;
+		TVecSwizzledData<T, 4, 3, 1> wy;
+		TVecSwizzledData<T, 4, 3, 2> wz;
+		TVecSwizzledData<T, 4, 3, 3> ww;
+		TVecSwizzledData<T, 4, 0, 0, 0> xxx;
+		TVecSwizzledData<T, 4, 0, 0, 1> xxy;
+		TVecSwizzledData<T, 4, 0, 0, 2> xxz;
+		TVecSwizzledData<T, 4, 0, 0, 3> xxw;
+		TVecSwizzledData<T, 4, 0, 1, 0> xyx;
+		TVecSwizzledData<T, 4, 0, 1, 1> xyy;
+		TVecSwizzledData<T, 4, 0, 1, 2> xyz;
+		TVecSwizzledData<T, 4, 0, 1, 3> xyw;
+		TVecSwizzledData<T, 4, 0, 2, 0> xzx;
+		TVecSwizzledData<T, 4, 0, 2, 1> xzy;
+		TVecSwizzledData<T, 4, 0, 2, 2> xzz;
+		TVecSwizzledData<T, 4, 0, 2, 3> xzw;
+		TVecSwizzledData<T, 4, 0, 3, 0> xwx;
+		TVecSwizzledData<T, 4, 0, 3, 1> xwy;
+		TVecSwizzledData<T, 4, 0, 3, 2> xwz;
+		TVecSwizzledData<T, 4, 0, 3, 3> xww;
+		TVecSwizzledData<T, 4, 1, 0, 0> yxx;
+		TVecSwizzledData<T, 4, 1, 0, 1> yxy;
+		TVecSwizzledData<T, 4, 1, 0, 2> yxz;
+		TVecSwizzledData<T, 4, 1, 0, 3> yxw;
+		TVecSwizzledData<T, 4, 1, 1, 0> yyx;
+		TVecSwizzledData<T, 4, 1, 1, 1> yyy;
+		TVecSwizzledData<T, 4, 1, 1, 2> yyz;
+		TVecSwizzledData<T, 4, 1, 1, 3> yyw;
+		TVecSwizzledData<T, 4, 1, 2, 0> yzx;
+		TVecSwizzledData<T, 4, 1, 2, 1> yzy;
+		TVecSwizzledData<T, 4, 1, 2, 2> yzz;
+		TVecSwizzledData<T, 4, 1, 2, 3> yzw;
+		TVecSwizzledData<T, 4, 1, 3, 0> ywx;
+		TVecSwizzledData<T, 4, 1, 3, 1> ywy;
+		TVecSwizzledData<T, 4, 1, 3, 2> ywz;
+		TVecSwizzledData<T, 4, 1, 3, 3> yww;
+		TVecSwizzledData<T, 4, 2, 0, 0> zxx;
+		TVecSwizzledData<T, 4, 2, 0, 1> zxy;
+		TVecSwizzledData<T, 4, 2, 0, 2> zxz;
+		TVecSwizzledData<T, 4, 2, 0, 3> zxw;
+		TVecSwizzledData<T, 4, 2, 1, 0> zyx;
+		TVecSwizzledData<T, 4, 2, 1, 1> zyy;
+		TVecSwizzledData<T, 4, 2, 1, 2> zyz;
+		TVecSwizzledData<T, 4, 2, 1, 3> zyw;
+		TVecSwizzledData<T, 4, 2, 2, 0> zzx;
+		TVecSwizzledData<T, 4, 2, 2, 1> zzy;
+		TVecSwizzledData<T, 4, 2, 2, 2> zzz;
+		TVecSwizzledData<T, 4, 2, 2, 3> zzw;
+		TVecSwizzledData<T, 4, 2, 3, 0> zwx;
+		TVecSwizzledData<T, 4, 2, 3, 1> zwy;
+		TVecSwizzledData<T, 4, 2, 3, 2> zwz;
+		TVecSwizzledData<T, 4, 2, 3, 3> zww;
+		TVecSwizzledData<T, 4, 3, 0, 0> wxx;
+		TVecSwizzledData<T, 4, 3, 0, 1> wxy;
+		TVecSwizzledData<T, 4, 3, 0, 2> wxz;
+		TVecSwizzledData<T, 4, 3, 0, 3> wxw;
+		TVecSwizzledData<T, 4, 3, 1, 0> wyx;
+		TVecSwizzledData<T, 4, 3, 1, 1> wyy;
+		TVecSwizzledData<T, 4, 3, 1, 2> wyz;
+		TVecSwizzledData<T, 4, 3, 1, 3> wyw;
+		TVecSwizzledData<T, 4, 3, 2, 0> wzx;
+		TVecSwizzledData<T, 4, 3, 2, 1> wzy;
+		TVecSwizzledData<T, 4, 3, 2, 2> wzz;
+		TVecSwizzledData<T, 4, 3, 2, 3> wzw;
+		TVecSwizzledData<T, 4, 3, 3, 0> wwx;
+		TVecSwizzledData<T, 4, 3, 3, 1> wwy;
+		TVecSwizzledData<T, 4, 3, 3, 2> wwz;
+		TVecSwizzledData<T, 4, 3, 3, 3> www;
+		TVecSwizzledData<T, 4, 0, 0, 0, 0> xxxx;
+		TVecSwizzledData<T, 4, 0, 0, 0, 1> xxxy;
+		TVecSwizzledData<T, 4, 0, 0, 0, 2> xxxz;
+		TVecSwizzledData<T, 4, 0, 0, 0, 3> xxxw;
+		TVecSwizzledData<T, 4, 0, 0, 1, 0> xxyx;
+		TVecSwizzledData<T, 4, 0, 0, 1, 1> xxyy;
+		TVecSwizzledData<T, 4, 0, 0, 1, 2> xxyz;
+		TVecSwizzledData<T, 4, 0, 0, 1, 3> xxyw;
+		TVecSwizzledData<T, 4, 0, 0, 2, 0> xxzx;
+		TVecSwizzledData<T, 4, 0, 0, 2, 1> xxzy;
+		TVecSwizzledData<T, 4, 0, 0, 2, 2> xxzz;
+		TVecSwizzledData<T, 4, 0, 0, 2, 3> xxzw;
+		TVecSwizzledData<T, 4, 0, 0, 3, 0> xxwx;
+		TVecSwizzledData<T, 4, 0, 0, 3, 1> xxwy;
+		TVecSwizzledData<T, 4, 0, 0, 3, 2> xxwz;
+		TVecSwizzledData<T, 4, 0, 0, 3, 3> xxww;
+		TVecSwizzledData<T, 4, 0, 1, 0, 0> xyxx;
+		TVecSwizzledData<T, 4, 0, 1, 0, 1> xyxy;
+		TVecSwizzledData<T, 4, 0, 1, 0, 2> xyxz;
+		TVecSwizzledData<T, 4, 0, 1, 0, 3> xyxw;
+		TVecSwizzledData<T, 4, 0, 1, 1, 0> xyyx;
+		TVecSwizzledData<T, 4, 0, 1, 1, 1> xyyy;
+		TVecSwizzledData<T, 4, 0, 1, 1, 2> xyyz;
+		TVecSwizzledData<T, 4, 0, 1, 1, 3> xyyw;
+		TVecSwizzledData<T, 4, 0, 1, 2, 0> xyzx;
+		TVecSwizzledData<T, 4, 0, 1, 2, 1> xyzy;
+		TVecSwizzledData<T, 4, 0, 1, 2, 2> xyzz;
+		TVecSwizzledData<T, 4, 0, 1, 2, 3> xyzw;
+		TVecSwizzledData<T, 4, 0, 1, 3, 0> xywx;
+		TVecSwizzledData<T, 4, 0, 1, 3, 1> xywy;
+		TVecSwizzledData<T, 4, 0, 1, 3, 2> xywz;
+		TVecSwizzledData<T, 4, 0, 1, 3, 3> xyww;
+		TVecSwizzledData<T, 4, 0, 2, 0, 0> xzxx;
+		TVecSwizzledData<T, 4, 0, 2, 0, 1> xzxy;
+		TVecSwizzledData<T, 4, 0, 2, 0, 2> xzxz;
+		TVecSwizzledData<T, 4, 0, 2, 0, 3> xzxw;
+		TVecSwizzledData<T, 4, 0, 2, 1, 0> xzyx;
+		TVecSwizzledData<T, 4, 0, 2, 1, 1> xzyy;
+		TVecSwizzledData<T, 4, 0, 2, 1, 2> xzyz;
+		TVecSwizzledData<T, 4, 0, 2, 1, 3> xzyw;
+		TVecSwizzledData<T, 4, 0, 2, 2, 0> xzzx;
+		TVecSwizzledData<T, 4, 0, 2, 2, 1> xzzy;
+		TVecSwizzledData<T, 4, 0, 2, 2, 2> xzzz;
+		TVecSwizzledData<T, 4, 0, 2, 2, 3> xzzw;
+		TVecSwizzledData<T, 4, 0, 2, 3, 0> xzwx;
+		TVecSwizzledData<T, 4, 0, 2, 3, 1> xzwy;
+		TVecSwizzledData<T, 4, 0, 2, 3, 2> xzwz;
+		TVecSwizzledData<T, 4, 0, 2, 3, 3> xzww;
+		TVecSwizzledData<T, 4, 0, 3, 0, 0> xwxx;
+		TVecSwizzledData<T, 4, 0, 3, 0, 1> xwxy;
+		TVecSwizzledData<T, 4, 0, 3, 0, 2> xwxz;
+		TVecSwizzledData<T, 4, 0, 3, 0, 3> xwxw;
+		TVecSwizzledData<T, 4, 0, 3, 1, 0> xwyx;
+		TVecSwizzledData<T, 4, 0, 3, 1, 1> xwyy;
+		TVecSwizzledData<T, 4, 0, 3, 1, 2> xwyz;
+		TVecSwizzledData<T, 4, 0, 3, 1, 3> xwyw;
+		TVecSwizzledData<T, 4, 0, 3, 2, 0> xwzx;
+		TVecSwizzledData<T, 4, 0, 3, 2, 1> xwzy;
+		TVecSwizzledData<T, 4, 0, 3, 2, 2> xwzz;
+		TVecSwizzledData<T, 4, 0, 3, 2, 3> xwzw;
+		TVecSwizzledData<T, 4, 0, 3, 3, 0> xwwx;
+		TVecSwizzledData<T, 4, 0, 3, 3, 1> xwwy;
+		TVecSwizzledData<T, 4, 0, 3, 3, 2> xwwz;
+		TVecSwizzledData<T, 4, 0, 3, 3, 3> xwww;
+		TVecSwizzledData<T, 4, 1, 0, 0, 0> yxxx;
+		TVecSwizzledData<T, 4, 1, 0, 0, 1> yxxy;
+		TVecSwizzledData<T, 4, 1, 0, 0, 2> yxxz;
+		TVecSwizzledData<T, 4, 1, 0, 0, 3> yxxw;
+		TVecSwizzledData<T, 4, 1, 0, 1, 0> yxyx;
+		TVecSwizzledData<T, 4, 1, 0, 1, 1> yxyy;
+		TVecSwizzledData<T, 4, 1, 0, 1, 2> yxyz;
+		TVecSwizzledData<T, 4, 1, 0, 1, 3> yxyw;
+		TVecSwizzledData<T, 4, 1, 0, 2, 0> yxzx;
+		TVecSwizzledData<T, 4, 1, 0, 2, 1> yxzy;
+		TVecSwizzledData<T, 4, 1, 0, 2, 2> yxzz;
+		TVecSwizzledData<T, 4, 1, 0, 2, 3> yxzw;
+		TVecSwizzledData<T, 4, 1, 0, 3, 0> yxwx;
+		TVecSwizzledData<T, 4, 1, 0, 3, 1> yxwy;
+		TVecSwizzledData<T, 4, 1, 0, 3, 2> yxwz;
+		TVecSwizzledData<T, 4, 1, 0, 3, 3> yxww;
+		TVecSwizzledData<T, 4, 1, 1, 0, 0> yyxx;
+		TVecSwizzledData<T, 4, 1, 1, 0, 1> yyxy;
+		TVecSwizzledData<T, 4, 1, 1, 0, 2> yyxz;
+		TVecSwizzledData<T, 4, 1, 1, 0, 3> yyxw;
+		TVecSwizzledData<T, 4, 1, 1, 1, 0> yyyx;
+		TVecSwizzledData<T, 4, 1, 1, 1, 1> yyyy;
+		TVecSwizzledData<T, 4, 1, 1, 1, 2> yyyz;
+		TVecSwizzledData<T, 4, 1, 1, 1, 3> yyyw;
+		TVecSwizzledData<T, 4, 1, 1, 2, 0> yyzx;
+		TVecSwizzledData<T, 4, 1, 1, 2, 1> yyzy;
+		TVecSwizzledData<T, 4, 1, 1, 2, 2> yyzz;
+		TVecSwizzledData<T, 4, 1, 1, 2, 3> yyzw;
+		TVecSwizzledData<T, 4, 1, 1, 3, 0> yywx;
+		TVecSwizzledData<T, 4, 1, 1, 3, 1> yywy;
+		TVecSwizzledData<T, 4, 1, 1, 3, 2> yywz;
+		TVecSwizzledData<T, 4, 1, 1, 3, 3> yyww;
+		TVecSwizzledData<T, 4, 1, 2, 0, 0> yzxx;
+		TVecSwizzledData<T, 4, 1, 2, 0, 1> yzxy;
+		TVecSwizzledData<T, 4, 1, 2, 0, 2> yzxz;
+		TVecSwizzledData<T, 4, 1, 2, 0, 3> yzxw;
+		TVecSwizzledData<T, 4, 1, 2, 1, 0> yzyx;
+		TVecSwizzledData<T, 4, 1, 2, 1, 1> yzyy;
+		TVecSwizzledData<T, 4, 1, 2, 1, 2> yzyz;
+		TVecSwizzledData<T, 4, 1, 2, 1, 3> yzyw;
+		TVecSwizzledData<T, 4, 1, 2, 2, 0> yzzx;
+		TVecSwizzledData<T, 4, 1, 2, 2, 1> yzzy;
+		TVecSwizzledData<T, 4, 1, 2, 2, 2> yzzz;
+		TVecSwizzledData<T, 4, 1, 2, 2, 3> yzzw;
+		TVecSwizzledData<T, 4, 1, 2, 3, 0> yzwx;
+		TVecSwizzledData<T, 4, 1, 2, 3, 1> yzwy;
+		TVecSwizzledData<T, 4, 1, 2, 3, 2> yzwz;
+		TVecSwizzledData<T, 4, 1, 2, 3, 3> yzww;
+		TVecSwizzledData<T, 4, 1, 3, 0, 0> ywxx;
+		TVecSwizzledData<T, 4, 1, 3, 0, 1> ywxy;
+		TVecSwizzledData<T, 4, 1, 3, 0, 2> ywxz;
+		TVecSwizzledData<T, 4, 1, 3, 0, 3> ywxw;
+		TVecSwizzledData<T, 4, 1, 3, 1, 0> ywyx;
+		TVecSwizzledData<T, 4, 1, 3, 1, 1> ywyy;
+		TVecSwizzledData<T, 4, 1, 3, 1, 2> ywyz;
+		TVecSwizzledData<T, 4, 1, 3, 1, 3> ywyw;
+		TVecSwizzledData<T, 4, 1, 3, 2, 0> ywzx;
+		TVecSwizzledData<T, 4, 1, 3, 2, 1> ywzy;
+		TVecSwizzledData<T, 4, 1, 3, 2, 2> ywzz;
+		TVecSwizzledData<T, 4, 1, 3, 2, 3> ywzw;
+		TVecSwizzledData<T, 4, 1, 3, 3, 0> ywwx;
+		TVecSwizzledData<T, 4, 1, 3, 3, 1> ywwy;
+		TVecSwizzledData<T, 4, 1, 3, 3, 2> ywwz;
+		TVecSwizzledData<T, 4, 1, 3, 3, 3> ywww;
+		TVecSwizzledData<T, 4, 2, 0, 0, 0> zxxx;
+		TVecSwizzledData<T, 4, 2, 0, 0, 1> zxxy;
+		TVecSwizzledData<T, 4, 2, 0, 0, 2> zxxz;
+		TVecSwizzledData<T, 4, 2, 0, 0, 3> zxxw;
+		TVecSwizzledData<T, 4, 2, 0, 1, 0> zxyx;
+		TVecSwizzledData<T, 4, 2, 0, 1, 1> zxyy;
+		TVecSwizzledData<T, 4, 2, 0, 1, 2> zxyz;
+		TVecSwizzledData<T, 4, 2, 0, 1, 3> zxyw;
+		TVecSwizzledData<T, 4, 2, 0, 2, 0> zxzx;
+		TVecSwizzledData<T, 4, 2, 0, 2, 1> zxzy;
+		TVecSwizzledData<T, 4, 2, 0, 2, 2> zxzz;
+		TVecSwizzledData<T, 4, 2, 0, 2, 3> zxzw;
+		TVecSwizzledData<T, 4, 2, 0, 3, 0> zxwx;
+		TVecSwizzledData<T, 4, 2, 0, 3, 1> zxwy;
+		TVecSwizzledData<T, 4, 2, 0, 3, 2> zxwz;
+		TVecSwizzledData<T, 4, 2, 0, 3, 3> zxww;
+		TVecSwizzledData<T, 4, 2, 1, 0, 0> zyxx;
+		TVecSwizzledData<T, 4, 2, 1, 0, 1> zyxy;
+		TVecSwizzledData<T, 4, 2, 1, 0, 2> zyxz;
+		TVecSwizzledData<T, 4, 2, 1, 0, 3> zyxw;
+		TVecSwizzledData<T, 4, 2, 1, 1, 0> zyyx;
+		TVecSwizzledData<T, 4, 2, 1, 1, 1> zyyy;
+		TVecSwizzledData<T, 4, 2, 1, 1, 2> zyyz;
+		TVecSwizzledData<T, 4, 2, 1, 1, 3> zyyw;
+		TVecSwizzledData<T, 4, 2, 1, 2, 0> zyzx;
+		TVecSwizzledData<T, 4, 2, 1, 2, 1> zyzy;
+		TVecSwizzledData<T, 4, 2, 1, 2, 2> zyzz;
+		TVecSwizzledData<T, 4, 2, 1, 2, 3> zyzw;
+		TVecSwizzledData<T, 4, 2, 1, 3, 0> zywx;
+		TVecSwizzledData<T, 4, 2, 1, 3, 1> zywy;
+		TVecSwizzledData<T, 4, 2, 1, 3, 2> zywz;
+		TVecSwizzledData<T, 4, 2, 1, 3, 3> zyww;
+		TVecSwizzledData<T, 4, 2, 2, 0, 0> zzxx;
+		TVecSwizzledData<T, 4, 2, 2, 0, 1> zzxy;
+		TVecSwizzledData<T, 4, 2, 2, 0, 2> zzxz;
+		TVecSwizzledData<T, 4, 2, 2, 0, 3> zzxw;
+		TVecSwizzledData<T, 4, 2, 2, 1, 0> zzyx;
+		TVecSwizzledData<T, 4, 2, 2, 1, 1> zzyy;
+		TVecSwizzledData<T, 4, 2, 2, 1, 2> zzyz;
+		TVecSwizzledData<T, 4, 2, 2, 1, 3> zzyw;
+		TVecSwizzledData<T, 4, 2, 2, 2, 0> zzzx;
+		TVecSwizzledData<T, 4, 2, 2, 2, 1> zzzy;
+		TVecSwizzledData<T, 4, 2, 2, 2, 2> zzzz;
+		TVecSwizzledData<T, 4, 2, 2, 2, 3> zzzw;
+		TVecSwizzledData<T, 4, 2, 2, 3, 0> zzwx;
+		TVecSwizzledData<T, 4, 2, 2, 3, 1> zzwy;
+		TVecSwizzledData<T, 4, 2, 2, 3, 2> zzwz;
+		TVecSwizzledData<T, 4, 2, 2, 3, 3> zzww;
+		TVecSwizzledData<T, 4, 2, 3, 0, 0> zwxx;
+		TVecSwizzledData<T, 4, 2, 3, 0, 1> zwxy;
+		TVecSwizzledData<T, 4, 2, 3, 0, 2> zwxz;
+		TVecSwizzledData<T, 4, 2, 3, 0, 3> zwxw;
+		TVecSwizzledData<T, 4, 2, 3, 1, 0> zwyx;
+		TVecSwizzledData<T, 4, 2, 3, 1, 1> zwyy;
+		TVecSwizzledData<T, 4, 2, 3, 1, 2> zwyz;
+		TVecSwizzledData<T, 4, 2, 3, 1, 3> zwyw;
+		TVecSwizzledData<T, 4, 2, 3, 2, 0> zwzx;
+		TVecSwizzledData<T, 4, 2, 3, 2, 1> zwzy;
+		TVecSwizzledData<T, 4, 2, 3, 2, 2> zwzz;
+		TVecSwizzledData<T, 4, 2, 3, 2, 3> zwzw;
+		TVecSwizzledData<T, 4, 2, 3, 3, 0> zwwx;
+		TVecSwizzledData<T, 4, 2, 3, 3, 1> zwwy;
+		TVecSwizzledData<T, 4, 2, 3, 3, 2> zwwz;
+		TVecSwizzledData<T, 4, 2, 3, 3, 3> zwww;
+		TVecSwizzledData<T, 4, 3, 0, 0, 0> wxxx;
+		TVecSwizzledData<T, 4, 3, 0, 0, 1> wxxy;
+		TVecSwizzledData<T, 4, 3, 0, 0, 2> wxxz;
+		TVecSwizzledData<T, 4, 3, 0, 0, 3> wxxw;
+		TVecSwizzledData<T, 4, 3, 0, 1, 0> wxyx;
+		TVecSwizzledData<T, 4, 3, 0, 1, 1> wxyy;
+		TVecSwizzledData<T, 4, 3, 0, 1, 2> wxyz;
+		TVecSwizzledData<T, 4, 3, 0, 1, 3> wxyw;
+		TVecSwizzledData<T, 4, 3, 0, 2, 0> wxzx;
+		TVecSwizzledData<T, 4, 3, 0, 2, 1> wxzy;
+		TVecSwizzledData<T, 4, 3, 0, 2, 2> wxzz;
+		TVecSwizzledData<T, 4, 3, 0, 2, 3> wxzw;
+		TVecSwizzledData<T, 4, 3, 0, 3, 0> wxwx;
+		TVecSwizzledData<T, 4, 3, 0, 3, 1> wxwy;
+		TVecSwizzledData<T, 4, 3, 0, 3, 2> wxwz;
+		TVecSwizzledData<T, 4, 3, 0, 3, 3> wxww;
+		TVecSwizzledData<T, 4, 3, 1, 0, 0> wyxx;
+		TVecSwizzledData<T, 4, 3, 1, 0, 1> wyxy;
+		TVecSwizzledData<T, 4, 3, 1, 0, 2> wyxz;
+		TVecSwizzledData<T, 4, 3, 1, 0, 3> wyxw;
+		TVecSwizzledData<T, 4, 3, 1, 1, 0> wyyx;
+		TVecSwizzledData<T, 4, 3, 1, 1, 1> wyyy;
+		TVecSwizzledData<T, 4, 3, 1, 1, 2> wyyz;
+		TVecSwizzledData<T, 4, 3, 1, 1, 3> wyyw;
+		TVecSwizzledData<T, 4, 3, 1, 2, 0> wyzx;
+		TVecSwizzledData<T, 4, 3, 1, 2, 1> wyzy;
+		TVecSwizzledData<T, 4, 3, 1, 2, 2> wyzz;
+		TVecSwizzledData<T, 4, 3, 1, 2, 3> wyzw;
+		TVecSwizzledData<T, 4, 3, 1, 3, 0> wywx;
+		TVecSwizzledData<T, 4, 3, 1, 3, 1> wywy;
+		TVecSwizzledData<T, 4, 3, 1, 3, 2> wywz;
+		TVecSwizzledData<T, 4, 3, 1, 3, 3> wyww;
+		TVecSwizzledData<T, 4, 3, 2, 0, 0> wzxx;
+		TVecSwizzledData<T, 4, 3, 2, 0, 1> wzxy;
+		TVecSwizzledData<T, 4, 3, 2, 0, 2> wzxz;
+		TVecSwizzledData<T, 4, 3, 2, 0, 3> wzxw;
+		TVecSwizzledData<T, 4, 3, 2, 1, 0> wzyx;
+		TVecSwizzledData<T, 4, 3, 2, 1, 1> wzyy;
+		TVecSwizzledData<T, 4, 3, 2, 1, 2> wzyz;
+		TVecSwizzledData<T, 4, 3, 2, 1, 3> wzyw;
+		TVecSwizzledData<T, 4, 3, 2, 2, 0> wzzx;
+		TVecSwizzledData<T, 4, 3, 2, 2, 1> wzzy;
+		TVecSwizzledData<T, 4, 3, 2, 2, 2> wzzz;
+		TVecSwizzledData<T, 4, 3, 2, 2, 3> wzzw;
+		TVecSwizzledData<T, 4, 3, 2, 3, 0> wzwx;
+		TVecSwizzledData<T, 4, 3, 2, 3, 1> wzwy;
+		TVecSwizzledData<T, 4, 3, 2, 3, 2> wzwz;
+		TVecSwizzledData<T, 4, 3, 2, 3, 3> wzww;
+		TVecSwizzledData<T, 4, 3, 3, 0, 0> wwxx;
+		TVecSwizzledData<T, 4, 3, 3, 0, 1> wwxy;
+		TVecSwizzledData<T, 4, 3, 3, 0, 2> wwxz;
+		TVecSwizzledData<T, 4, 3, 3, 0, 3> wwxw;
+		TVecSwizzledData<T, 4, 3, 3, 1, 0> wwyx;
+		TVecSwizzledData<T, 4, 3, 3, 1, 1> wwyy;
+		TVecSwizzledData<T, 4, 3, 3, 1, 2> wwyz;
+		TVecSwizzledData<T, 4, 3, 3, 1, 3> wwyw;
+		TVecSwizzledData<T, 4, 3, 3, 2, 0> wwzx;
+		TVecSwizzledData<T, 4, 3, 3, 2, 1> wwzy;
+		TVecSwizzledData<T, 4, 3, 3, 2, 2> wwzz;
+		TVecSwizzledData<T, 4, 3, 3, 2, 3> wwzw;
+		TVecSwizzledData<T, 4, 3, 3, 3, 0> wwwx;
+		TVecSwizzledData<T, 4, 3, 3, 3, 1> wwwy;
+		TVecSwizzledData<T, 4, 3, 3, 3, 2> wwwz;
+		TVecSwizzledData<T, 4, 3, 3, 3, 3> wwww;
+	};
+};
+
+#if ANKI_COMPILER_MSVC
+#	pragma warning(pop)
+#elif ANKI_COMPILER_GCC_COMPATIBLE
+#	pragma GCC diagnostic pop
+#endif
+
+template<typename T, U32 kTComponentCount>
+class TVec : public TVecData<T, kTComponentCount>
+{
+public:
+	static constexpr Bool kVec4Simd = kTComponentCount == 4 && std::is_same<T, F32>::value && ANKI_ENABLE_SIMD;
+	static constexpr Bool kIsInteger = std::is_integral<T>::value;
+
+	using Base = TVecData<T, kTComponentCount>;
+	using Base::m_arr;
+	using Base::m_simd;
+
+	// Constructors
+
+	constexpr TVec()
+		: TVec(T(0))
+	{
+	}
+
+	explicit TVec(T f)
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			m_simd = _mm_set1_ps(f);
+#else
+			m_simd = vdupq_n_f32(f);
+#endif
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; ++i)
+			{
+				m_arr[i] = f;
+			}
+		}
+	}
+
+	// Copy
+	TVec(const TVec& b)
+	{
+		if constexpr(kVec4Simd)
+		{
+			m_simd = b.m_simd;
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				m_arr[i] = b.m_arr[i];
+			}
+		}
+	}
+
+	// Convert from another type. From int to float vectors and the opposite.
+	template<typename Y>
+	explicit TVec(TVec<Y, kTComponentCount> b) requires(!std::is_same<Y, T>::value)
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			m_arr[i] = T(b[i]);
+		}
+	}
+
+	explicit TVec(T arr[])
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			m_simd = _mm_load_ps(arr);
+#else
+			m_simd = vld1q_f32(arr);
+#endif
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; ++i)
+			{
+				m_arr[i] = arr[i];
+			}
+		}
+	}
+
+	explicit TVec(const Array<T, kTComponentCount>& arr)
+		: TVec(arr.getBegin())
+	{
+	}
+
+	// Vec2 specific
+
+	constexpr TVec(T x, T y) requires(kTComponentCount == 2)
+		: Base{x, y}
+	{
+	}
+
+	// Vec2 specific
+
+	constexpr TVec(T x, T y, T z) requires(kTComponentCount == 3)
+		: Base{x, y, z}
+	{
+	}
+
+	constexpr TVec(TVec<T, 2> a, T z) requires(kTComponentCount == 3)
+		: Base{a.m_arr[0], a.m_arr[1], z}
+	{
+	}
+
+	constexpr TVec(T x, TVec<T, 2> a) requires(kTComponentCount == 3)
+		: Base{x, a.m_arr[0], a.m_arr[1]}
+	{
+	}
+
+	// Vec4 specific
+
+	explicit TVec(T x, T y, T z, T w) requires(kTComponentCount == 4)
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			m_simd = _mm_set_ps(w, z, y, x);
+#else
+			alignas(16) T data[4] = {x, y, z, w};
+			m_simd = vld1q_f32(data);
+#endif
+		}
+		else
+		{
+			this->m_arr = {x, y, z, w};
+		}
+	}
+
+	constexpr TVec(TVec<T, 3> a, T w) requires(kTComponentCount == 4)
+		: Base{a.m_arr[0], a.m_arr[1], a.m_arr[2], w}
+	{
+	}
+
+	constexpr TVec(T x, TVec<T, 3> a) requires(kTComponentCount == 4)
+		: Base{x, a.m_arr[0], a.m_arr[1], a.m_arr[2]}
+	{
+	}
+
+	constexpr TVec(TVec<T, 2> a, T z, T w) requires(kTComponentCount == 4)
+		: Base{a.m_arr[0], a.m_arr[1], z, w}
+	{
+	}
+
+	constexpr TVec(T x, TVec<T, 2> a, T w) requires(kTComponentCount == 4)
+		: Base{x, a.m_arr[0], a.m_arr[1], w}
+	{
+	}
+
+	constexpr TVec(T x, T y, TVec<T, 2> a) requires(kTComponentCount == 4)
+		: Base{x, y, a.m_arr[0], a.m_arr[1]}
+	{
+	}
+
+	constexpr TVec(TVec<T, 2> a, TVec<T, 2> b) requires(kTComponentCount == 4)
+		: Base{a.m_arr[0], a.m_arr[1], b.m_arr[0], b.m_arr[1]}
+	{
+	}
+
+	explicit TVec(Base::Simd simd) requires(kTComponentCount == 4)
+	{
+		m_simd = simd;
+	}
+
+	// Accessors
+
+	T& operator[](U32 i)
+	{
+		return m_arr[i];
+	}
+
+	T operator[](U32 i) const
+	{
+		return m_arr[i];
+	}
+
+	// Operators with the same type
+
+	// Copy
+	TVec& operator=(const TVec& b)
+	{
+		if constexpr(kVec4Simd)
+		{
+			m_simd = b.m_simd;
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				m_arr[i] = b.m_carr[i];
+			}
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator+(TVec b) const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			return TVec(_mm_add_ps(m_simd, b.m_simd));
+#else
+			return TVec(vaddq_f32(m_simd, b.m_simd));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				out.m_arr[i] = m_arr[i] + b.m_arr[i];
+			}
+
+			return out;
+		}
+	}
+
+	TVec& operator+=(TVec b)
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			m_simd = _mm_add_ps(m_simd, b.m_simd);
+#else
+			m_simd = vaddq_f32(m_simd, b.m_simd);
+#endif
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				m_arr[i] += b.m_arr[i];
+			}
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator-(TVec b) const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			return TVec(_mm_sub_ps(m_simd, b.m_simd));
+#else
+			return TVec(vsubq_f32(m_simd, b.m_simd));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				out.m_arr[i] = m_arr[i] - b.m_arr[i];
+			}
+			return out;
+		}
+	}
+
+	TVec& operator-=(TVec b)
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			m_simd = _mm_sub_ps(m_simd, b.m_simd);
+#else
+			m_simd = vsubq_f32(m_simd, b.m_simd);
+#endif
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				m_arr[i] -= b.m_arr[i];
+			}
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator*(TVec b) const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			return TVec(_mm_mul_ps(m_simd, b.m_simd));
+#else
+			return TVec(vmulq_f32(m_simd, b.m_simd));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				out.m_arr[i] = m_arr[i] * b.m_arr[i];
+			}
+			return out;
+		}
+	}
+
+	TVec& operator*=(TVec b)
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			m_simd = _mm_mul_ps(m_simd, b.m_simd);
+#else
+			m_simd = vmulq_f32(m_simd, b.m_simd);
+#endif
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				m_arr[i] *= b.m_arr[i];
+			}
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator/(TVec b) const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			return TVec(_mm_div_ps(m_simd, b.m_simd));
+#else
+			return TVec(vdivq_f32(m_simd, b.m_simd));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				ANKI_ASSERT(b.m_arr[i] != 0.0);
+				out.m_arr[i] = m_arr[i] / b.m_arr[i];
+			}
+			return out;
+		}
+	}
+
+	TVec& operator/=(TVec b)
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			m_simd = _mm_div_ps(m_simd, b.m_simd);
+#else
+			m_simd = vdivq_f32(m_simd, b.m_simd);
+#endif
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				ANKI_ASSERT(b.m_arr[i] != 0.0);
+				m_arr[i] /= b.m_arr[i];
+			}
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator-() const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			return TVec(_mm_xor_ps(m_simd, _mm_set1_ps(-0.0)));
+#else
+			return TVec(veorq_s32(m_simd, vdupq_n_f32(-0.0)));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				out.m_arr[i] = -m_arr[i];
+			}
+			return out;
+		}
+	}
+
+	[[nodiscard]] TVec operator<<(TVec b) const requires(kIsInteger)
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			out.m_arr[i] = m_arr[i] << b.m_arr[i];
+		}
+		return out;
+	}
+
+	TVec& operator<<=(TVec b) requires(kIsInteger)
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			m_arr[i] <<= b.m_arr[i];
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator>>(TVec b) const requires(kIsInteger)
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			out.m_arr[i] = m_arr[i] >> b.m_arr[i];
+		}
+		return out;
+	}
+
+	TVec& operator>>=(TVec b) requires(kIsInteger)
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			m_arr[i] >>= b.m_arr[i];
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator&(TVec b) const requires(kIsInteger)
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			out.m_arr[i] = m_arr[i] & b.m_arr[i];
+		}
+		return out;
+	}
+
+	TVec& operator&=(TVec b) requires(kIsInteger)
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			m_arr[i] &= b.m_arr[i];
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator|(TVec b) const requires(kIsInteger)
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			out.m_arr[i] = m_arr[i] | b.m_arr[i];
+		}
+		return out;
+	}
+
+	TVec& operator|=(TVec b) requires(kIsInteger)
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			m_arr[i] |= b.m_arr[i];
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator^(TVec b) const requires(kIsInteger)
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			out.m_arr[i] = m_arr[i] ^ b.m_arr[i];
+		}
+		return out;
+	}
+
+	TVec& operator^=(TVec b) requires(kIsInteger)
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			m_arr[i] ^= b.m_arr[i];
+		}
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator%(TVec b) const requires(kIsInteger)
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			out.m_arr[i] = m_arr[i] % b.m_arr[i];
+		}
+		return out;
+	}
+
+	TVec& operator%=(TVec b) requires(kIsInteger)
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			m_arr[i] %= b.m_arr[i];
+		}
+		return *this;
+	}
+
+	[[nodiscard]] Bool operator==(TVec b) const
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			if(!isZero<T>(m_arr[i] - b.m_arr[i]))
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	[[nodiscard]] Bool operator!=(TVec b) const
+	{
+		return !operator==(b);
+	}
+
+	[[nodiscard]] Bool operator<(TVec b) const
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			if(m_arr[i] >= b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	[[nodiscard]] Bool operator<=(TVec b) const
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			if(m_arr[i] > b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	[[nodiscard]] Bool operator>(TVec b) const
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			if(m_arr[i] <= b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	[[nodiscard]] Bool operator>=(TVec b) const
+	{
+		for(U i = 0; i < kTComponentCount; i++)
+		{
+			if(m_arr[i] < b.m_arr[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	// Operators with T
+
+	[[nodiscard]] TVec operator+(T f) const
+	{
+		return (*this) + TVec(f);
+	}
+
+	TVec& operator+=(T f)
+	{
+		(*this) += TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator-(T f) const
+	{
+		return (*this) - TVec(f);
+	}
+
+	TVec& operator-=(T f)
+	{
+		(*this) -= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator*(T f) const
+	{
+		return (*this) * TVec(f);
+	}
+
+	TVec& operator*=(T f)
+	{
+		(*this) *= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator/(T f) const
+	{
+		return (*this) / TVec(f);
+	}
+
+	TVec& operator/=(T f)
+	{
+		(*this) /= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator<<(T f) const requires(kIsInteger)
+	{
+		return (*this) << TVec(f);
+	}
+
+	TVec& operator<<=(T f) requires(kIsInteger)
+	{
+		(*this) <<= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator>>(T f) const requires(kIsInteger)
+	{
+		return (*this) >> TVec(f);
+	}
+
+	TVec& operator>>=(T f) requires(kIsInteger)
+	{
+		(*this) >>= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator&(T f) const requires(kIsInteger)
+	{
+		return (*this) & TVec(f);
+	}
+
+	TVec& operator&=(T f) requires(kIsInteger)
+	{
+		(*this) &= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator|(T f) const requires(kIsInteger)
+	{
+		return (*this) | TVec(f);
+	}
+
+	TVec& operator|=(T f) requires(kIsInteger)
+	{
+		(*this) |= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator^(T f) const requires(kIsInteger)
+	{
+		return (*this) ^ TVec(f);
+	}
+
+	TVec& operator^=(T f) requires(kIsInteger)
+	{
+		(*this) ^= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] TVec operator%(T f) const requires(kIsInteger)
+	{
+		return (*this) % TVec(f);
+	}
+
+	TVec& operator%=(T f) requires(kIsInteger)
+	{
+		(*this) %= TVec(f);
+		return *this;
+	}
+
+	[[nodiscard]] Bool operator==(T f) const
+	{
+		return *this == TVec(f);
+	}
+
+	[[nodiscard]] Bool operator!=(T f) const
+	{
+		return *this != TVec(f);
+	}
+
+	[[nodiscard]] Bool operator<(T f) const
+	{
+		return *this < TVec(f);
+	}
+
+	[[nodiscard]] Bool operator<=(T f) const
+	{
+		return *this <= TVec(f);
+	}
+
+	[[nodiscard]] Bool operator>(T f) const
+	{
+		return *this > TVec(f);
+	}
+
+	[[nodiscard]] Bool operator>=(T f) const
+	{
+		return *this >= TVec(f);
+	}
+
+	// Operators with other
+
+	[[nodiscard]] TVec operator*(const TMat<T, 4, 4>& m4) const requires(kTComponentCount == 4)
+	{
+		TVec out;
+		out.x = this->x * m4(0, 0) + this->y * m4(1, 0) + this->z * m4(2, 0) + this->w * m4(3, 0);
+		out.y = this->x * m4(0, 1) + this->y * m4(1, 1) + this->z * m4(2, 1) + this->w * m4(3, 1);
+		out.z = this->x * m4(0, 2) + this->y * m4(1, 2) + this->z * m4(2, 2) + this->w * m4(3, 2);
+		out.w = this->x * m4(0, 3) + this->y * m4(1, 3) + this->z * m4(2, 3) + this->w * m4(3, 3);
+		return out;
+	}
+
+	// Other
+
+	[[nodiscard]] T dot(TVec b) const
+	{
+		T out = T(0);
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			_mm_store_ss(&out, _mm_dp_ps(m_simd, b.m_simd, 0xF1));
+#else
+			out = vaddvq_f32(vmulq_f32(m_simd, b.m_simd));
+#endif
+		}
+		else
+		{
+			for(U i = 0; i < kTComponentCount; i++)
+			{
+				out += m_arr[i] * b.m_arr[i];
+			}
+		}
+		return out;
+	}
+
+	// 6 muls, 3 adds
+	[[nodiscard]] TVec cross(TVec b) const requires(kTComponentCount == 3)
+	{
+		return TVec(this->y * b.z - this->z * b.y, this->z * b.x - this->x * b.z, this->x * b.y - this->y * b.x);
+	}
+
+	// It's like calculating the cross of a 3 component TVec.
+	[[nodiscard]] TVec cross(TVec b_) const requires(kTComponentCount == 4)
+	{
+		ANKI_ASSERT(this->w == T(0));
+		ANKI_ASSERT(b_.w() == T(0));
+
+#if ANKI_SIMD_SSE
+		const auto& a = m_simd;
+		const auto& b = b_.m_simd;
+
+		__m128 t1 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 2, 1));
+		t1 = _mm_mul_ps(t1, a);
+		__m128 t2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 2, 1));
+		t2 = _mm_mul_ps(t2, b);
+		__m128 t3 = _mm_sub_ps(t1, t2);
+
+		return TVec(_mm_shuffle_ps(t3, t3, _MM_SHUFFLE(0, 0, 2, 1))).xyz0;
+#elif ANKI_SIMD_NEON
+		const auto& a = m_simd;
+		const auto& b = b_.m_simd;
+
+		float32x4_t t1 = ANKI_NEON_SHUFFLE_F32x4(b, b, 0, 0, 2, 1);
+		t1 = vmulq_f32(t1, a);
+		float32x4_t t2 = ANKI_NEON_SHUFFLE_F32x4(a, a, 0, 0, 2, 1);
+		t2 = vmulq_f32(t2, b);
+		float32x4_t t3 = vsubq_f32(t1, t2);
+
+		return TVec(ANKI_NEON_SHUFFLE_F32x4(t3, t3, 0, 0, 2, 1)).xyz0;
+#else
+		return TVec(xyz.cross(b_.xyz), T(0));
+#endif
+	}
+
+	[[nodiscard]] TVec projectTo(TVec toThis) const requires(kTComponentCount == 3 || kTComponentCount == 2)
+	{
+		return toThis * ((*this).dot(toThis) / (toThis.dot(toThis)));
+	}
+
+	[[nodiscard]] TVec projectTo(TVec toThis) const requires(kTComponentCount == 4)
+	{
+		ANKI_ASSERT(this->w == T(0));
+		return (toThis * ((*this).dot(toThis) / (toThis.dot(toThis)))).xyz0;
+	}
+
+	[[nodiscard]] TVec projectTo(TVec rayOrigin, TVec rayDir) const requires(kTComponentCount == 3 || kTComponentCount == 2)
+	{
+		const auto& a = *this;
+		return rayOrigin + rayDir * ((a - rayOrigin).dot(rayDir));
+	}
+
+	[[nodiscard]] TVec projectTo(TVec rayOrigin, TVec rayDir) const requires(kTComponentCount == 4)
+	{
+		ANKI_ASSERT(this->w == T(0));
+		ANKI_ASSERT(rayOrigin.w() == T(0));
+		ANKI_ASSERT(rayDir.w() == T(0));
+		const auto& a = *this;
+		return rayOrigin + rayDir * ((a - rayOrigin).dot(rayDir));
+	}
+
+	// Perspective divide. Divide the xyzw of this to the w of this. This method will handle some edge cases.
+	[[nodiscard]] TVec perspectiveDivide() const requires(kTComponentCount == 4)
+	{
+		auto invw = T(1) / this->w; // This may become (+-)inf
+		invw = (invw > 1e+11) ? 1e+11 : invw; // Clamp
+		invw = (invw < -1e+11) ? -1e+11 : invw; // Clamp
+		return (*this) * invw;
+	}
+
+	[[nodiscard]] T lengthSquared() const
+	{
+		return dot(*this);
+	}
+
+	[[nodiscard]] T length() const
+	{
+		return sqrt<T>(lengthSquared());
+	}
+
+	[[nodiscard]] T distanceSquared(TVec b) const
+	{
+		return ((*this) - b).lengthSquared();
+	}
+
+	[[nodiscard]] T distance(TVec b) const
+	{
+		return sqrt<T>(distance(b));
+	}
+
+	[[nodiscard]] TVec normalize() const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			__m128 v = _mm_dp_ps(m_simd, m_simd, 0xFF);
+			v = _mm_sqrt_ps(v);
+			v = _mm_div_ps(m_simd, v);
+			return TVec(v);
+#else
+			float32x4_t v = vmulq_f32(m_simd, m_simd);
+			v = vdupq_n_f32(vaddvq_f32(v));
+			v = vsqrtq_f32(v);
+			v = vdivq_f32(m_simd, v);
+			return TVec(v);
+#endif
+		}
+		else
+		{
+			return (*this) / length();
+		}
+	}
+
+	// Return lerp(this, v1, t)
+	[[nodiscard]] TVec lerp(TVec v1, TVec t) const
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; ++i)
+		{
+			out[i] = m_arr[i] * (T(1) - t.m_arr[i]) + v1.m_arr[i] * t.m_arr[i];
+		}
+		return out;
+	}
+
+	// Return lerp(this, v1, t)
+	[[nodiscard]] TVec lerp(TVec v1, T t) const
+	{
+		return ((*this) * (T(1) - t)) + (v1 * t);
+	}
+
+	[[nodiscard]] TVec abs() const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			const __m128 signMask = _mm_set1_ps(-0.0f);
+			return TVec(_mm_andnot_ps(signMask, m_simd));
+#else
+			return TVec(vabsq_f32(m_simd));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; ++i)
+			{
+				out[i] = absolute<T>(m_arr[i]);
+			}
+			return out;
+		}
+	}
+
+	// Get clamped between two values.
+	[[nodiscard]] TVec clamp(T minv, T maxv) const
+	{
+		return max(TVec(minv)).min(TVec(maxv));
+	}
+
+	// Get clamped between two vectors.
+	[[nodiscard]] TVec clamp(TVec minv, TVec maxv) const
+	{
+		return max(minv).min(maxv);
+	}
+
+	// Get the min of all components.
+	[[nodiscard]] TVec min(TVec b) const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			return TVec(_mm_min_ps(m_simd, b.m_simd));
+#else
+			return TVec(vminq_f32(m_simd, b.m_simd));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; ++i)
+			{
+				out[i] = anki::min<T>(m_arr[i], b[i]);
+			}
+			return out;
+		}
+	}
+
+	// Get the min of all components.
+	[[nodiscard]] TVec min(T b) const
+	{
+		return min(TVec(b));
+	}
+
+	// Get the max of all components.
+	[[nodiscard]] TVec max(TVec b) const
+	{
+		if constexpr(kVec4Simd)
+		{
+#if ANKI_SIMD_SSE
+			return TVec(_mm_max_ps(m_simd, b.m_simd));
+#else
+			return TVec(vmaxq_f32(m_simd, b.m_simd));
+#endif
+		}
+		else
+		{
+			TVec out;
+			for(U i = 0; i < kTComponentCount; ++i)
+			{
+				out[i] = anki::max<T>(m_arr[i], b[i]);
+			}
+			return out;
+		}
+	}
+
+	// Get the max of all components.
+	[[nodiscard]] TVec max(T b) const
+	{
+		return max(TVec(b));
+	}
+
+	[[nodiscard]] TVec round() const requires(!kIsInteger)
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; ++i)
+		{
+			out[i] = T(::round(m_arr[i]));
+		}
+		return out;
+	}
+
+	// Get a safe 1 / (*this)
+	[[nodiscard]] TVec reciprocal() const
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; ++i)
+		{
+			out[i] = T(1) / m_arr[i];
+		}
+		return out;
+	}
+
+	// Power
+	[[nodiscard]] TVec pow(TVec b) const
+	{
+		TVec out;
+		for(U i = 0; i < kTComponentCount; ++i)
+		{
+			out[i] = anki::pow(m_arr[i], b.m_arr[i]);
+		}
+		return out;
+	}
+
+	// Power
+	[[nodiscard]] TVec pow(T b) const
+	{
+		return pow(TVec(b));
+	}
+
+	[[nodiscard]] static TVec xAxis() requires(kTComponentCount == 2)
+	{
+		return TVec(T(1), T(0));
+	}
+
+	[[nodiscard]] static TVec xAxis() requires(kTComponentCount == 3)
+	{
+		return TVec(T(1), T(0), T(0));
+	}
+
+	[[nodiscard]] static TVec xAxis() requires(kTComponentCount == 4)
+	{
+		return TVec(T(1), T(0), T(0), T(0));
+	}
+
+	[[nodiscard]] static TVec yAxis() requires(kTComponentCount == 2)
+	{
+		return TVec(T(0), T(1));
+	}
+
+	[[nodiscard]] static TVec yAxis() requires(kTComponentCount == 3)
+	{
+		return TVec(T(0), T(1), T(0));
+	}
+
+	[[nodiscard]] static TVec yAxis() requires(kTComponentCount == 4)
+	{
+		return TVec(T(0), T(1), T(0), T(0));
+	}
+
+	[[nodiscard]] static TVec zAxis() requires(kTComponentCount == 3)
+	{
+		return TVec(T(0), T(0), T(1));
+	}
+
+	[[nodiscard]] static TVec zAxis() requires(kTComponentCount == 4)
+	{
+		return TVec(T(0), T(0), T(1), T(0));
+	}
+
+	// Serialize the structure.
+	void serialize(void* data, PtrSize& size) const
+	{
+		size = sizeof(*this);
+		if(data)
+		{
+			memcpy(data, this, sizeof(*this));
+		}
+	}
+
+	// De-serialize the structure.
+	void deserialize(const void* data)
+	{
+		ANKI_ASSERT(data);
+		memcpy(this, data, sizeof(*this));
+	}
+
+	[[nodiscard]] static constexpr U8 getSize()
+	{
+		return U8(kTComponentCount);
+	}
+
+	[[nodiscard]] String toString() const requires(std::is_floating_point<T>::value)
+	{
+		String str;
+		for(U i = 0; i < kTComponentCount; ++i)
+		{
+			str += String().sprintf((i < i - kTComponentCount) ? "%f " : "%f", m_arr[i]);
+		}
+		return str;
+	}
+
+	static constexpr Bool kClangWorkaround = std::is_integral<T>::value && std::is_unsigned<T>::value;
+	[[nodiscard]] String toString() const requires(kClangWorkaround)
+	{
+		String str;
+		for(U i = 0; i < kTComponentCount; ++i)
+		{
+			str += String().sprintf((i < i - kTComponentCount) ? "%u " : "%u", m_arr[i]);
+		}
+		return str;
+	}
+
+	static constexpr Bool kClangWorkaround2 = std::is_integral<T>::value && std::is_signed<T>::value;
+	[[nodiscard]] String toString() const requires(kClangWorkaround2)
+	{
+		String str;
+		for(U i = 0; i < kTComponentCount; ++i)
+		{
+			str += String().sprintf((i < i - kTComponentCount) ? "%d " : "%d", m_arr[i]);
+		}
+		return str;
+	}
+};
+
+template<typename T, U kTComponentCount>
+TVec<T, kTComponentCount> operator+(T f, TVec<T, kTComponentCount> v)
+{
+	return v + f;
+}
+
+template<typename T, U kTComponentCount>
+TVec<T, kTComponentCount> operator-(T f, TVec<T, kTComponentCount> v)
+{
+	return TVec<T, kTComponentCount>(f) - v;
+}
+
+template<typename T, U kTComponentCount>
+TVec<T, kTComponentCount> operator*(T f, TVec<T, kTComponentCount> v)
+{
+	return v * f;
+}
+
+template<typename T, U kTComponentCount>
+TVec<T, kTComponentCount> operator/(T f, TVec<T, kTComponentCount> v)
+{
+	return TVec<T, kTComponentCount>(f) / v;
+}
+
+// All vectors
+using Vec2 = TVec<F32, 2>;
+using HVec2 = TVec<F16, 2>;
+using IVec2 = TVec<I32, 2>;
+using I16Vec2 = TVec<I16, 2>;
+using I8Vec2 = TVec<I8, 2>;
+using UVec2 = TVec<U32, 2>;
+using U16Vec2 = TVec<U16, 2>;
+using U8Vec2 = TVec<U8, 2>;
+using Vec3 = TVec<F32, 3>;
+using HVec3 = TVec<F16, 3>;
+using IVec3 = TVec<I32, 3>;
+using I16Vec3 = TVec<I16, 3>;
+using I8Vec3 = TVec<I8, 3>;
+using UVec3 = TVec<U32, 3>;
+using U16Vec3 = TVec<U16, 3>;
+using U8Vec3 = TVec<U8, 3>;
+using Vec4 = TVec<F32, 4>;
+using HVec4 = TVec<F16, 4>;
+using IVec4 = TVec<I32, 4>;
+using I16Vec4 = TVec<I16, 4>;
+using I8Vec4 = TVec<I8, 4>;
+using UVec4 = TVec<U32, 4>;
+using U16Vec4 = TVec<U16, 4>;
+using U8Vec4 = TVec<U8, 4>;
+
+} // end namespace v2
+} // end namespace anki

+ 2 - 3
AnKi/Resource/ResourceFilesystem.cpp

@@ -477,7 +477,7 @@ Error ResourceFilesystem::openFileInternal(const ResourceFilename& filename, Res
 				continue;
 			}
 
-			CString pfname = fsfile.m_filename;
+			[[maybe_unused]] CString pfname = fsfile.m_filename;
 			ANKI_ASSERT(pfname == filename);
 
 			// Found
@@ -557,8 +557,7 @@ ResourceString ResourceFilesystem::getFileFullPath(ResourceFilename filename) co
 				continue;
 			}
 
-			CString pfname = fsfile.m_filename;
-			ANKI_ASSERT(pfname == filename);
+			ANKI_ASSERT(fsfile.m_filename == filename);
 
 			if(!p.m_isArchive && !p.m_isSpecial)
 			{

+ 21 - 0
Tests/Script/LuaBinder.cpp

@@ -106,3 +106,24 @@ print(vec:getX(), vec:getY(), vec:getZ())
 
 	ScriptManager::freeSingleton();
 }
+
+ANKI_TEST(Script, Fields)
+{
+	ScriptManager::allocateSingleton(allocAligned, nullptr);
+
+	{
+		ScriptEnvironment env;
+
+		static const char* script = R"(
+vec = Vec3.new(1, 2, 3)
+vec:setX(6)
+logi(string.format("%f %f %f", vec:getX(), vec:getY(), vec:getZ()))
+vec.blah = 0
+x = vec.x
+)";
+
+		ANKI_TEST_EXPECT_NO_ERR(env.evalString(script));
+	}
+
+	ScriptManager::freeSingleton();
+}